From 04f34516f89451b5a3af6a122f740dc30112e597 Mon Sep 17 00:00:00 2001 From: Romain LE DISEZ Date: Tue, 23 Jun 2009 10:05:15 +0200 Subject: Improve compatibility with other RDBMS --- modules/search/helpers/search.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/search/helpers/search.php b/modules/search/helpers/search.php index 15efa3b2..9046ad2d 100644 --- a/modules/search/helpers/search.php +++ b/modules/search/helpers/search.php @@ -45,7 +45,7 @@ class search_Core { "WHERE MATCH({search_records}.`data`) AGAINST ('$q' IN BOOLEAN MODE) " . $access_sql . "ORDER BY `score` DESC " . - "LIMIT $offset, $limit"; + "LIMIT $limit OFFSET $offset"; return array($count, new ORM_Iterator(ORM::factory("item"), $db->query($query))); } -- cgit v1.2.3 From 2e6a1d6fdc562b2ff797deaf8b8ab019c17ed113 Mon Sep 17 00:00:00 2001 From: Romain LE DISEZ Date: Tue, 23 Jun 2009 10:08:55 +0200 Subject: SQL is case insensitive --- modules/search/helpers/search.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/search/helpers/search.php b/modules/search/helpers/search.php index 9046ad2d..ea8dad81 100644 --- a/modules/search/helpers/search.php +++ b/modules/search/helpers/search.php @@ -34,11 +34,11 @@ class search_Core { // Count the total number of rows. We can't do this with our regular query because of the // limit statement. It's possible that if we get rid of the limit (but keep the offset) on // the 2nd query and combine the two, it might be faster than making 2 separate queries. - $count_query = "SELECT COUNT(*) AS C " . + $count_query = "SELECT COUNT(*) AS c " . "FROM {items} JOIN {search_records} ON ({items}.`id` = {search_records}.`item_id`) " . "WHERE MATCH({search_records}.`data`) AGAINST ('$q' IN BOOLEAN MODE) " . $access_sql; - $count = $db->query($count_query)->current()->C; + $count = $db->query($count_query)->current()->c; $query = "SELECT {items}.*, MATCH({search_records}.`data`) AGAINST ('$q') AS `score` " . "FROM {items} JOIN {search_records} ON ({items}.`id` = {search_records}.`item_id`) " . -- cgit v1.2.3 From c80d2da0a95a63b76f5a4c835f1a0e1022ec2f53 Mon Sep 17 00:00:00 2001 From: Romain LE DISEZ Date: Tue, 23 Jun 2009 10:09:46 +0200 Subject: Remove an useless ORDER BY. It improves compatibility with PgSQL. --- modules/gallery/models/item.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/modules/gallery/models/item.php b/modules/gallery/models/item.php index 7dce9e51..44d79d5b 100644 --- a/modules/gallery/models/item.php +++ b/modules/gallery/models/item.php @@ -382,8 +382,7 @@ class Item_Model extends ORM_MPTT { SELECT COUNT(*) AS position FROM {items} WHERE parent_id = {$this->id} AND {$this->sort_column} <= (SELECT {$this->sort_column} - FROM {items} WHERE id = $child_id) - ORDER BY {$this->sort_column} {$this->sort_order}"); + FROM {items} WHERE id = $child_id)"); return $result->current()->position; } -- cgit v1.2.3 From d601ab93beb9be2cc69d64fa04803ff3c3601c3a Mon Sep 17 00:00:00 2001 From: Romain LE DISEZ Date: Tue, 23 Jun 2009 10:12:09 +0200 Subject: Value stored in comment.state is not 15 char length. Use a VARCHAR instead of a CHAR. It improves compatibility with PgSQL. --- installer/install.sql | 2 +- modules/comment/helpers/comment_installer.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/installer/install.sql b/installer/install.sql index 432aee64..b9c56043 100755 --- a/installer/install.sql +++ b/installer/install.sql @@ -55,7 +55,7 @@ CREATE TABLE {comments} ( `server_remote_addr` varchar(32) default NULL, `server_remote_host` varchar(64) default NULL, `server_remote_port` varchar(16) default NULL, - `state` char(15) default 'unpublished', + `state` varchar(15) default 'unpublished', `text` text, `updated` int(9) NOT NULL, PRIMARY KEY (`id`) diff --git a/modules/comment/helpers/comment_installer.php b/modules/comment/helpers/comment_installer.php index b1cfcdc0..58bce8e0 100644 --- a/modules/comment/helpers/comment_installer.php +++ b/modules/comment/helpers/comment_installer.php @@ -43,7 +43,7 @@ class comment_installer { `server_remote_addr` varchar(32) default NULL, `server_remote_host` varchar(64) default NULL, `server_remote_port` varchar(16) default NULL, - `state` char(15) default 'unpublished', + `state` varchar(15) default 'unpublished', `text` text, `updated` int(9) NOT NULL, PRIMARY KEY (`id`)) -- cgit v1.2.3 From de28b0350e5d5bf6c3e1eb5a9531298b08fd7cba Mon Sep 17 00:00:00 2001 From: Romain LE DISEZ Date: Tue, 23 Jun 2009 10:14:38 +0200 Subject: Use an integer because the code store 0 and 1. It improves compatiblity with PgSQL. The right way is to use a BOOLEAN and code with booleans. The values would be : - FALSE => deny - TRUE => allow - NULL => unknow --- modules/gallery/helpers/access.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/gallery/helpers/access.php b/modules/gallery/helpers/access.php index c48f0b79..7b01058c 100644 --- a/modules/gallery/helpers/access.php +++ b/modules/gallery/helpers/access.php @@ -426,7 +426,7 @@ class access_Core { $field = "{$perm_name}_{$group->id}"; $cache_table = $perm_name == "view" ? "items" : "access_caches"; $db->query("ALTER TABLE {{$cache_table}} ADD `$field` SMALLINT NOT NULL DEFAULT 0"); - $db->query("ALTER TABLE {access_intents} ADD `$field` BOOLEAN DEFAULT NULL"); + $db->query("ALTER TABLE {access_intents} ADD `$field` SMALLINT DEFAULT NULL"); $db->update("access_intents", array($field => 0), array("item_id" => 1)); ORM::factory("access_intent")->clear_cache(); } -- cgit v1.2.3 From be354ab98bbb08abad0a7efd6fb1d110e11381de Mon Sep 17 00:00:00 2001 From: Romain LE DISEZ Date: Wed, 24 Jun 2009 23:40:47 +0200 Subject: Remove an useless ORDER BY. It improves compatibility with PgSQL. (Replay of c80d2da0a95a63b76f5a4c835f1a0e1022ec2f53) --- modules/gallery/models/item.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/modules/gallery/models/item.php b/modules/gallery/models/item.php index 430119b5..7dbbbcb1 100644 --- a/modules/gallery/models/item.php +++ b/modules/gallery/models/item.php @@ -389,8 +389,7 @@ class Item_Model extends ORM_MPTT { SELECT COUNT(*) AS position FROM {items} WHERE parent_id = {$this->id} AND `{$this->sort_column}` $comp (SELECT `{$this->sort_column}` - FROM {items} WHERE id = $child_id) - ORDER BY `{$this->sort_column}` {$this->sort_order}")->current()->position; + FROM {items} WHERE id = $child_id)")->current()->position; // We stopped short of our target value in the sort (notice that we're using a < comparator // above) because it's possible that we have duplicate values in the sort column. An -- cgit v1.2.3 From 923732ca4dca6db218f6252a7133cd72f98fa086 Mon Sep 17 00:00:00 2001 From: Romain LE DISEZ Date: Thu, 25 Jun 2009 10:07:12 +0200 Subject: Go back to the upstream version because we choosed to use real booleans. --- modules/gallery/helpers/access.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/gallery/helpers/access.php b/modules/gallery/helpers/access.php index 7b01058c..c48f0b79 100644 --- a/modules/gallery/helpers/access.php +++ b/modules/gallery/helpers/access.php @@ -426,7 +426,7 @@ class access_Core { $field = "{$perm_name}_{$group->id}"; $cache_table = $perm_name == "view" ? "items" : "access_caches"; $db->query("ALTER TABLE {{$cache_table}} ADD `$field` SMALLINT NOT NULL DEFAULT 0"); - $db->query("ALTER TABLE {access_intents} ADD `$field` SMALLINT DEFAULT NULL"); + $db->query("ALTER TABLE {access_intents} ADD `$field` BOOLEAN DEFAULT NULL"); $db->update("access_intents", array($field => 0), array("item_id" => 1)); ORM::factory("access_intent")->clear_cache(); } -- cgit v1.2.3 From d192f2f1bc1227938d3144381ef311c7e07b47b0 Mon Sep 17 00:00:00 2001 From: Tim Almdal Date: Wed, 15 Jul 2009 20:38:37 +0800 Subject: Fix for ticket #545. Changed get_db_info.html.php to not display the database information request form until the var directory is successfully tested as writable. This prevents users from thinking they can enter the database information prior to successfully accessing the var directory. Signed-off-by: Tim Almdal --- installer/views/get_db_info.html.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/installer/views/get_db_info.html.php b/installer/views/get_db_info.html.php index 7835f246..94c19585 100644 --- a/installer/views/get_db_info.html.php +++ b/installer/views/get_db_info.html.php @@ -26,6 +26,7 @@ +
Database @@ -87,3 +88,4 @@
+ -- cgit v1.2.3 From f6973431b7f8df24c081a03c7c989f621ab2a708 Mon Sep 17 00:00:00 2001 From: Tim Almdal Date: Wed, 15 Jul 2009 21:48:47 +0800 Subject: Fix for ticket #544. * Separate the portion of get_db_info.html.php that displays the status of the var directory into a separate view var_dir_status.html.php * Change the processing to always generate the database information request screen unless there is an environment error, the var directory is not writable and the install was successful Signed-off-by: Tim Almdal --- installer/views/get_db_info.html.php | 43 ++++----------------------------- installer/views/install.html.php | 3 ++- installer/views/var_dir_status.html.php | 30 +++++++++++++++++++++++ installer/web.php | 21 ++++++++++------ 4 files changed, 50 insertions(+), 47 deletions(-) create mode 100644 installer/views/var_dir_status.html.php diff --git a/installer/views/get_db_info.html.php b/installer/views/get_db_info.html.php index 94c19585..adc775a4 100644 --- a/installer/views/get_db_info.html.php +++ b/installer/views/get_db_info.html.php @@ -1,32 +1,4 @@ -

Welcome!

-

- Installing Gallery is very easy. We just need to know how to talk - to your MySQL database, and we need a place to store your photos on - your web host. -

- - -
- Photo Storage - -

- We're having trouble creating a place for your photos. Can you - help? Please create a directory called "var" using mkdir var in your - gallery3 directory, then run chmod 777 var. That - should fix it. -

- Check again -

- -

- We've found a place to store your photos: - -

- -
- -
Database @@ -41,7 +13,7 @@ Database Name - + @@ -49,7 +21,7 @@ User - + @@ -57,7 +29,7 @@ Password - + @@ -65,7 +37,7 @@ Host - + @@ -73,19 +45,14 @@ Table Prefix - + - - - (Please fix the photo storage problem before continuing) -
- diff --git a/installer/views/install.html.php b/installer/views/install.html.php index a0eddaf3..31112c28 100644 --- a/installer/views/install.html.php +++ b/installer/views/install.html.php @@ -8,7 +8,8 @@
- + +
  • - +
  • -- cgit v1.2.3 From 3aea4dd118208d6d7859ebf1d32249a8644b655b Mon Sep 17 00:00:00 2001 From: Bharat Mediratta Date: Mon, 20 Jul 2009 18:47:32 -0700 Subject: Dump out the error message along with the stack trace when we catch an exception from View::render() --- modules/gallery/libraries/MY_View.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/modules/gallery/libraries/MY_View.php b/modules/gallery/libraries/MY_View.php index 84ee0892..43783158 100644 --- a/modules/gallery/libraries/MY_View.php +++ b/modules/gallery/libraries/MY_View.php @@ -38,8 +38,7 @@ class View extends View_Core { try { return parent::render($print, $renderer); } catch (Exception $e) { - Kohana::Log('error', $e->getTraceAsString()); - Kohana::Log('debug', $e->getMessage()); + Kohana::Log("error", $e->getMessage() . "\n" . $e->getTraceAsString()); return ""; } } -- cgit v1.2.3 From 1a96ce145cfa529708852a46d4cab3c0d4d1b37e Mon Sep 17 00:00:00 2001 From: Bharat Mediratta Date: Mon, 20 Jul 2009 20:47:47 -0700 Subject: Don't let the task status message exceed the size of the status column when there's an error. --- modules/gallery/helpers/task.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/gallery/helpers/task.php b/modules/gallery/helpers/task.php index 6a9f63c2..352fe522 100644 --- a/modules/gallery/helpers/task.php +++ b/modules/gallery/helpers/task.php @@ -87,7 +87,7 @@ class task_Core { $task->log($e->__toString()); $task->state = "error"; $task->done = true; - $task->status = $e->getMessage(); + $task->status = substr($e->getMessage(), 0, 255); $task->save(); } -- cgit v1.2.3 From 329b6ce28ce0424303fece0fa0f542a0f1cb39ae Mon Sep 17 00:00:00 2001 From: Chad Kieffer Date: Mon, 20 Jul 2009 23:06:08 -0600 Subject: Fire vAlign after gQuick ajax load is complete. --- themes/default/js/ui.init.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/themes/default/js/ui.init.js b/themes/default/js/ui.init.js index b7508ee5..11cd06ed 100644 --- a/themes/default/js/ui.init.js +++ b/themes/default/js/ui.init.js @@ -57,7 +57,7 @@ $(document).ready(function() { if ($("#gAlbumGrid").length) { // Vertical align thumbnails/metadata in album grid $(".gItem").vAlign(); - $(".gItem").change(function(){ + $(".gQuick").ajaxStop(function(){ $(".gItem").vAlign(); }); } -- cgit v1.2.3 From 653badc2e1b9753f29bbb1d9fec8098716a4a2f4 Mon Sep 17 00:00:00 2001 From: hiwilson Date: Tue, 21 Jul 2009 09:44:51 +0800 Subject: set wmode='transparent' other than flowplayer.js (cherry picked from commit 79a46658196a98a3972983cc422d1ee544b09d4a) --- modules/gallery/views/movieplayer.html.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/modules/gallery/views/movieplayer.html.php b/modules/gallery/views/movieplayer.html.php index e8cabd31..28324a54 100644 --- a/modules/gallery/views/movieplayer.html.php +++ b/modules/gallery/views/movieplayer.html.php @@ -1,7 +1,8 @@ file_url(true), "", $attrs) ?> -- cgit v1.2.3 From 5a0424f458323578a6b2e5395a58f3d2bfc034dc Mon Sep 17 00:00:00 2001 From: Shai Ben-Naphtali Date: Tue, 21 Jul 2009 03:30:21 +0800 Subject: Fix some consistency in text. This fixes ticket #546 Signed-off-by: Bharat Mediratta --- modules/organize/controllers/organize.php | 4 ++-- modules/server_add/controllers/server_add.php | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/modules/organize/controllers/organize.php b/modules/organize/controllers/organize.php index 27852904..898be509 100644 --- a/modules/organize/controllers/organize.php +++ b/modules/organize/controllers/organize.php @@ -516,7 +516,7 @@ class Organize_Controller extends Controller { break; case "delete": - return array("description" => t("Delete selected photos and albums"), + return array("description" => t("Delete selected photos / albums"), "name" => t("Delete images in %name", array("name" => $item->title)), "type" => "delete", "runningMsg" => t("Delete images in progress"), @@ -537,4 +537,4 @@ class Organize_Controller extends Controller { throw new Exception("Operation '$operation' is not implmented"); } } -} \ No newline at end of file +} diff --git a/modules/server_add/controllers/server_add.php b/modules/server_add/controllers/server_add.php index 0be0f698..f68392ce 100644 --- a/modules/server_add/controllers/server_add.php +++ b/modules/server_add/controllers/server_add.php @@ -239,7 +239,7 @@ class Server_Add_Controller extends Admin_Controller { $entry->save(); } $task->set("completed_files", $completed_files); - $task->status = t("Adding photos and albums (%completed of %total)", + $task->status = t("Adding photos / albums (%completed of %total)", array("completed" => $completed_files, "total" => $total_files)); $task->percent_complete = 10 + 100 * ($completed_files / $total_files); @@ -252,7 +252,7 @@ class Server_Add_Controller extends Admin_Controller { $task->percent_complete = 100; ORM::factory("server_add_file")->where("task_id", $task->id)->delete_all(); message::info(t2("Successfully added one photo / album", - "Successfully added %count photos and albums", + "Successfully added %count photos / albums", $task->get("completed_files"))); } } -- cgit v1.2.3 From b99774ac49999e4701f1c410f0018a417a5f613e Mon Sep 17 00:00:00 2001 From: Shai Ben-Naphtali Date: Tue, 21 Jul 2009 12:13:13 +0800 Subject: Fixed grammer and set lowercase for the word project (minor change) Signed-off-by: Bharat Mediratta --- modules/gallery/views/after_install.html.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/gallery/views/after_install.html.php b/modules/gallery/views/after_install.html.php index d6ba8e7c..e4842163 100644 --- a/modules/gallery/views/after_install.html.php +++ b/modules/gallery/views/after_install.html.php @@ -21,7 +21,7 @@

    - Gallery website has news and information about Gallery Project and community.", array("url" => "http://gallery.menalto.com")) ?> + Gallery website has news and information about the Gallery project and community.", array("url" => "http://gallery.menalto.com")) ?>

    -- cgit v1.2.3 From ce963c9db00c25b3c1e6add1fe6032aef61a5bed Mon Sep 17 00:00:00 2001 From: Bharat Mediratta Date: Mon, 20 Jul 2009 22:23:21 -0700 Subject: Remove the access permission call from here; this is too low level. --- modules/tag/helpers/tag.php | 1 - 1 file changed, 1 deletion(-) diff --git a/modules/tag/helpers/tag.php b/modules/tag/helpers/tag.php index 1fb2e940..5efa6a19 100644 --- a/modules/tag/helpers/tag.php +++ b/modules/tag/helpers/tag.php @@ -85,7 +85,6 @@ class tag_Core { * @return array */ static function item_tags($item) { - access::required("view", $item); $tags = array(); foreach (Database::instance() ->select("name") -- cgit v1.2.3 From 050c82cf80b06a555252efaf701434b0cfd59bed Mon Sep 17 00:00:00 2001 From: Bharat Mediratta Date: Tue, 21 Jul 2009 11:09:23 -0700 Subject: Escape bare & symbols so that we use valid entities. Fixes ticket #577. --- modules/organize/views/organize.html.php | 2 +- modules/server_add/views/admin_server_add.html.php | 2 +- modules/server_add/views/server_add_tree_dialog.html.php | 2 +- modules/user/views/login.html.php | 2 +- themes/admin_default/views/admin.html.php | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/modules/organize/views/organize.html.php b/modules/organize/views/organize.html.php index 65d67d04..1686d255 100644 --- a/modules/organize/views/organize.html.php +++ b/modules/organize/views/organize.html.php @@ -33,7 +33,7 @@ var CONFIRM_DELETE = "

    "> + ref="">
      diff --git a/modules/server_add/views/admin_server_add.html.php b/modules/server_add/views/admin_server_add.html.php index 588a9fca..30ab3536 100644 --- a/modules/server_add/views/admin_server_add.html.php +++ b/modules/server_add/views/admin_server_add.html.php @@ -11,7 +11,7 @@
        $path): ?>
      • - " + " id="icon_" class="gRemoveDir ui-icon ui-icon-trash"> X diff --git a/modules/server_add/views/server_add_tree_dialog.html.php b/modules/server_add/views/server_add_tree_dialog.html.php index 21952849..a4eda3b9 100644 --- a/modules/server_add/views/server_add_tree_dialog.html.php +++ b/modules/server_add/views/server_add_tree_dialog.html.php @@ -1,7 +1,7 @@
      • - " + " id="gLogoutLink">
      • diff --git a/themes/admin_default/views/admin.html.php b/themes/admin_default/views/admin.html.php index 575f8a96..b0ddb6c5 100644 --- a/themes/admin_default/views/admin.html.php +++ b/themes/admin_default/views/admin.html.php @@ -45,7 +45,7 @@ admin_header_top() ?>
        • ')) ?>
        • - " + " id="gLogoutLink">
        • -- cgit v1.2.3 From 0546f0df13471664255a18b45c7464cc7f7f370e Mon Sep 17 00:00:00 2001 From: Bharat Mediratta Date: Tue, 21 Jul 2009 13:39:40 -0700 Subject: Fix the bug that the quick menu fires for the wrong photo. This stems from using a single gQuickPane
          that we move around. A race condition happens when you mouse over two thumbnails quickly. Whichever server response loses the race gets displayed, and sometimes it's the one that you're no longer hovering over. Fix it by changing gQuickPane to be a class and creating a
          per thumbnail. Fixes ticket #290. --- modules/gallery/css/quick.css | 12 ++++++------ modules/gallery/js/quick.js | 20 ++++++++------------ modules/gallery/views/quick_pane.html.php | 2 +- themes/default/css/fix-ie.css | 4 ++-- 4 files changed, 17 insertions(+), 21 deletions(-) diff --git a/modules/gallery/css/quick.css b/modules/gallery/css/quick.css index 0e45eac2..f153d475 100644 --- a/modules/gallery/css/quick.css +++ b/modules/gallery/css/quick.css @@ -1,4 +1,4 @@ -#gQuickPane { +.gQuickPane { position: absolute; top: 0; left: 0; @@ -17,7 +17,7 @@ padding: 0 !important; } -#gQuickPane { +.gQuickPane { background: #000; border-bottom: 1px solid #ccc; opacity: 0.9; @@ -26,19 +26,19 @@ left: 0; } -#gQuickPane a { +.gQuickPane a { cursor: pointer; float: left; margin: 4px; } -#gQuickPaneOptions { +.gQuickPaneOptions { background: #000; float: left; width: 100%; } -#gQuickPaneOptions li a { +.gQuickPaneOptions li a { display: block; float: none; width: auto; @@ -47,6 +47,6 @@ text-align: left; } -#gQuickPaneOptions li a:hover { +.gQuickPaneOptions li a:hover { background-color: #4d4d4d; } diff --git a/modules/gallery/js/quick.js b/modules/gallery/js/quick.js index 3ac97f8e..fda6470f 100644 --- a/modules/gallery/js/quick.js +++ b/modules/gallery/js/quick.js @@ -12,15 +12,15 @@ var show_quick = function() { var cont = $(this); var quick = $(this).find(".gQuick"); var img = cont.find(".gThumbnail,.gResize"); - $("#gQuickPane").remove(); - cont.append("
          "); - $("#gQuickPane").hide(); - cont.hover(function() {}, hide_quick); + cont.find(".gQuickPane").remove(); + cont.append("
          "); + cont.find(".gQuickPane").hide(); + cont.hover(function() {}, function() { cont.find(".gQuickPane").remove(); }); $.get( quick.attr("href"), {}, function(data, textStatus) { - $("#gQuickPane").html(data).slideDown("fast"); + cont.find(".gQuickPane").html(data).slideDown("fast"); $(".ui-state-default").hover( function() { $(this).addClass("ui-state-hover"); @@ -29,13 +29,13 @@ var show_quick = function() { $(this).removeClass("ui-state-hover"); } ); - $("#gQuickPane a:not(.options)").click(function(e) { + cont.find(".gQuickPane a:not(.options)").click(function(e) { e.preventDefault(); quick_do(cont, $(this), img); }); - $("#gQuickPane a.options").click(function(e) { + cont.find(".gQuickPane a.options").click(function(e) { e.preventDefault(); - $("#gQuickPaneOptions").slideToggle("fast"); + cont.find(".gQuickPaneOptions").slideToggle("fast"); }); } ); @@ -76,7 +76,3 @@ var quick_do = function(cont, pane, img) { } return false; }; - -var hide_quick = function() { - $("#gQuickPane").remove(); -}; diff --git a/modules/gallery/views/quick_pane.html.php b/modules/gallery/views/quick_pane.html.php index eabf4a67..e5469696 100644 --- a/modules/gallery/views/quick_pane.html.php +++ b/modules/gallery/views/quick_pane.html.php @@ -15,7 +15,7 @@ -
          -
            "> +
          diff --git a/modules/organize/views/organize_tree.html.php b/modules/organize/views/organize_tree.html.php index d64410d8..28b45be0 100644 --- a/modules/organize/views/organize_tree.html.php +++ b/modules/organize/views/organize_tree.html.php @@ -1,11 +1,11 @@
        • + "> +
          gBranchText"> - - title) ?>
          @@ -13,9 +13,7 @@
            "> - - - +
        • -- cgit v1.2.3 From 397468c47b8fc3fefeb54ff19a73980ed1dd8c20 Mon Sep 17 00:00:00 2001 From: Tim Almdal Date: Wed, 5 Aug 2009 09:23:32 -0700 Subject: Revert "Checkpoint the organize module rewrite. At this point, it doesn't really do" This reverts commit a25f08d433d504a53763feb358a1aa7f5f798de6. --- modules/organize/controllers/organize.php | 507 ++++++++++++++- modules/organize/css/organize.css | 184 +++++- modules/organize/helpers/organize_task.php | 131 ++++ modules/organize/helpers/organize_theme.php | 3 +- modules/organize/js/organize.js | 697 ++++++++++++++++++--- modules/organize/js/organize_init.js | 29 + modules/organize/views/organize.html.php | 53 ++ modules/organize/views/organize_album.html.php | 17 + .../organize/views/organize_button_pane.html.php | 49 +- modules/organize/views/organize_dialog.html.php | 37 -- modules/organize/views/organize_edit.html.php | 14 + .../organize/views/organize_thumb_grid.html.php | 23 +- modules/organize/views/organize_tree.html.php | 20 +- 13 files changed, 1532 insertions(+), 232 deletions(-) create mode 100644 modules/organize/helpers/organize_task.php create mode 100644 modules/organize/js/organize_init.js create mode 100644 modules/organize/views/organize.html.php create mode 100644 modules/organize/views/organize_album.html.php delete mode 100644 modules/organize/views/organize_dialog.html.php create mode 100644 modules/organize/views/organize_edit.html.php diff --git a/modules/organize/controllers/organize.php b/modules/organize/controllers/organize.php index d7854c53..898be509 100644 --- a/modules/organize/controllers/organize.php +++ b/modules/organize/controllers/organize.php @@ -19,48 +19,54 @@ */ class Organize_Controller extends Controller { private static $_MICRO_THUMB_SIZE = 90; - private static $_MICRO_THUMB_PADDING = 10; + private static $_MICRO_THUMB_PADDING = 5; - function index($item_id) { + function index($item_id=1) { $item = ORM::factory("item", $item_id); $root = ($item->id == 1) ? $item : ORM::factory("item", 1); access::required("view", $item); access::required("edit", $item); - $v = new View("organize_dialog.html"); + $v = new View("organize.html"); $v->root = $root; $v->item = $item; - $v->album_tree = $this->_tree($item, $root); - $v->micro_thumb_grid = $this->_get_micro_thumb_grid($item); + $v->album_tree = $this->tree($item, $root); $v->button_pane = new View("organize_button_pane.html"); - $buttons = (object)array("left" => array(), "middle" =>array(), "right" => array(), - "item" => $item); - module::event("organize_format_button_pane", $buttons); - - $v->button_pane->buttons = $buttons; print $v; } - function content($item_id, $offset=0) { + function content($item_id) { $item = ORM::factory("item", $item_id); access::required("view", $item); access::required("edit", $item); - $v = $this->_get_micro_thumb_grid($item, $offset); - print $v->__toString(); - } + $width = $this->input->get("width"); + $height = $this->input->get("height"); + $offset = $this->input->get("offset", 0); + $thumbsize = self::$_MICRO_THUMB_SIZE + 2 * self::$_MICRO_THUMB_PADDING; + $page_size = ceil($width / $thumbsize) * ceil($height / $thumbsize); - private function _get_micro_thumb_grid($item, $offset=0) { $v = new View("organize_thumb_grid.html"); - $v->item_id = $item->id; - $v->children = $item->children(25, $offset); + $v->children = $item->children($page_size, $offset); $v->thumbsize = self::$_MICRO_THUMB_SIZE; - $v->offset = $offset + 25; + $v->padding = self::$_MICRO_THUMB_PADDING; + $v->offset = $offset; + + print json_encode(array("count" => $v->children->count(), + "data" => $v->__toString())); + } + + function header($item_id) { + $item = ORM::factory("item", $item_id); + access::required("view", $item); + access::required("edit", $item); - return $v; + print json_encode( + array("title" => p::purify($item->title), + "description" => empty($item->description) ? "" : p::purify($item->description))); } - private function _tree($item, $parent, $selected=false) { + function tree($item, $parent) { access::required("view", $item); access::required("edit", $item); @@ -69,25 +75,466 @@ class Organize_Controller extends Controller { ->orderby(array("title" => "ASC")) ->find_all(); - $v = new View("organize_tree.html"); + $v = new View("organize_album.html"); $v->album = $parent; + $v->selected = $parent->id == $item->id; + + if ($albums->count()) { + $v->album_icon = $parent->id == 1 || $v->selected ? "ui-icon-minus" : "ui-icon-plus"; + } else { + $v->album_icon = ""; + } - $v->selected = false; $v->children = ""; - $v->album_icon = "ui-icon-plus"; - if (!$selected) { - $v->selected = $parent->id == $item->id; + foreach ($albums as $album) { + $v->children .= $this->tree($item, $album); + } + return $v->__toString(); + } + + function startTask($operation, $id) { + access::verify_csrf(); + $items = $this->input->post("item"); + + $item = ORM::factory("item", $id); + access::required("view", $item); + access::required("edit", $item); + + $definition = $this->_getOperationDefinition($item, $operation); + + $task_def = Task_Definition::factory() + ->callback("organize_task::run") + ->description($definition["description"]) + ->name($definition["name"]); + $task = task::create($task_def, array("items" => $items, "position" => 0, "target" => $id, + "type" => $definition["type"], + "batch" => ceil(count($items) * .1))); + // @todo If there is only one item then call task_run($task->id); Maybe even change js so + // we can call finish as well. + batch::start(); + print json_encode( + array("result" => "started", + "runningMsg" => $definition["runningMsg"], + "pauseMsg" => "
          {$definition['pauseMsg']}
          ", + "resumeMsg" => "
          {$definition['resumeMsg']}
          ", + "task" => array("id" => $task->id, + "percent_complete" => $task->percent_complete, + "type" => $task->get("type"), + "status" => $task->status, + "state" => $task->state, + "done" => $task->done))); + } + + function runTask($task_id) { + access::verify_csrf(); + + $task = task::run($task_id); + if (!$task->loaded || $task->owner_id != user::active()->id) { + access::forbidden(); + } + + print json_encode(array("result" => $task->done ? $task->state : "in_progress", + "task" => array("id" => $task->id, + "percent_complete" => $task->percent_complete, + "type" => $task->get("type"), + "post_process" => $task->get("post_process"), + "status" => $task->status, + "state" => $task->state, + "done" => $task->done))); + } + + function finishTask($task_id) { + access::verify_csrf(); + + $task = ORM::factory("task", $task_id); + if (!$task->loaded || $task->owner_id != user::active()->id) { + access::forbidden(); + } - if ($albums->count() && ($parent->id == 1 || $v->selected) ) { - $v->album_icon = "ui-icon-minus"; + if ($task->done) { + $item = ORM::factory("item", (int)$task->get("target")); + $type = $task->get("type"); + switch ($type) { + case "albumCover": + $task->status = t("Album cover set for '%album'", array("album" => $item->title)); + break; + case "delete": + $task->status = t("Selection deleted"); + break; + case "move": + $task->status = t("Move to '%album' completed", array("album" => $item->title)); + break; + case "rearrange": + try { + $item->sort_column = "weight"; + $item->save(); + $task->status = t("Rearrange for '%album' completed", array("album" => $item->title)); + } catch (Exception $e) { + $task->state = "error"; + $task->status = $e->getMessage(); + } + break; + case "rotateCcw": + case "rotateCw": + $task->status = t("Rotation completed"); + break; } + $task->save(); + } - foreach ($albums as $album) { - $v->children .= $this->_tree($item, $album, $v->selected); + batch::stop(); + print json_encode(array("result" => "success", + "task" => array( + "id" => $task->id, + "percent_complete" => $task->percent_complete, + "status" => $task->status, + "state" => $task->state, + "done" => $task->done))); + } + + function cancelTask($task_id) { + access::verify_csrf(); + + $task = ORM::factory("task", $task_id); + if (!$task->loaded || $task->owner_id != user::active()->id) { + access::forbidden(); + } + + if (!$task->done) { + $task->done = 1; + $task->state = "cancelled"; + $type = $task->get("type"); + switch ($type) { + case "move": + $task->status = t("Move to album was cancelled prior to completion"); + break; + case "rearrange": + $task->status = t("Rearrange album was cancelled prior to completion"); + case "rotateCcw": + case "rotateCw": + $task->status = t("Rotation was cancelled prior to completion"); + break; } + $task->save(); } - return $v->__toString(); + + batch::stop(); + print json_encode(array("result" => "success", + "task" => array( + "id" => $task->id, + "percent_complete" => $task->percent_complete, + "status" => $task->status, + "state" => $task->state, + "done" => $task->done))); + } + + function editForm() { + $event_parms = new stdClass(); + $event_parms->panes = array(); + $event_parms->itemids = $this->input->get("item"); + + // The following code should be done more dynamically i.e. use the event mechanism + if (count($event_parms->itemids) == 1) { + $item = ORM::factory("item") + ->in("id", $event_parms->itemids[0]) + ->find(); + + access::required("view", $item); + access::required("edit", $item); + + $event_parms->panes[] = array( + "label" => $item->is_album() ? t("Edit Album") : t("Edit Photo"), + "content" => organize::get_general_edit_form($item)); + + if ($item->is_album()) { + $event_parms->panes[] = array("label" => t("Sort Order"), + "content" => organize::get_sort_edit_form($item)); + } + } + + $event_parms->panes[] = array("label" => t("Manage Tags"), + "content" => organize::get_tag_form($event_parms->itemids)); + + $v = new View("organize_edit.html"); + $v->panes = $event_parms->panes; + print $v->render(); + } + + // Handlers for the album/photo edit. Probably should be in modules/gallery + public function general() { + access::verify_csrf(); + + $itemids = $this->input->post("item"); + $item = ORM::factory("item") + ->in("id", $itemids[0]) + ->find(); + access::required("view", $item); + access::required("edit", $item); + + $form = organize::get_general_edit_form($item); + if ($form->validate()) { + $orig = clone $item; + $item->title = $form->title->value; + $item->description = $form->description->value; + $item->rename($form->dirname->value); + $item->save(); + + if ($item->is_album()) { + log::success("content", "Updated album", "id\">view"); + $message = t("Saved album %album_title", array("album_title" => p::purify($item->title))); + } else { + log::success("content", "Updated photo", "id\">view"); + $message = t("Saved photo %photo_title", array("photo_title" => p::purify($item->title))); + } + print json_encode(array("form" => $form->__toString(), "message" => $message)); + } else { + print json_encode(array("form" => $form->__toString())); + } + } + + public function reset_general() { + $itemids = Input::instance()->get("item"); + $item = ORM::factory("item") + ->in("id", $itemids[0]) + ->find(); + access::required("view", $item); + access::required("edit", $item); + + print organize::get_general_edit_form($item); + } + + public function sort() { + access::verify_csrf(); + + $itemids = $this->input->post("item"); + $item = ORM::factory("item") + ->in("id", $itemids[0]) + ->find(); + access::required("view", $item); + access::required("edit", $item); + + $form = organize::get_sort_edit_form($item); + if ($form->validate()) { + $orig = clone $item; + $item->sort_column = $form->column->value; + $item->sort_order = $form->direction->value; + $item->save(); + + log::success("content", "Updated album", "id\">view"); + $message = t("Saved album %album_title", array("album_title" => p::purify($item->title))); + print json_encode(array("form" => $form->__toString(), "message" => $message)); + } else { + print json_encode(array("form" => $form->__toString())); + } + } + + public function reset_sort() { + $itemids = Input::instance()->get("item"); + $item = ORM::factory("item") + ->in("id", $itemids[0]) + ->find(); + access::required("view", $item); + access::required("edit", $item); + + print organize::get_sort_edit_form($item); + } + + public function edit_tags() { + access::verify_csrf(); + + $itemids = explode("|", $this->input->post("item")); + $form = organize::get_tag_form($itemids); + $old_tags = $form->tags->value; + if ($form->validate()) { + + $old_tags = preg_split("/[;,\s]+/", $old_tags); + sort($old_tags); + $new_tags = preg_split("/[;,\s]+/", $form->tags->value); + sort($new_tags); + + $HIGH_VALUE_STRING = "\256"; + for ($old_index = $new_index = 0;;) { + $old_tag = $old_index >= count($old_tags) ? $HIGH_VALUE_STRING : $old_tags[$old_index]; + $new_tag = $new_index >= count($new_tags) ? $HIGH_VALUE_STRING : $new_tags[$new_index]; + if ($old_tag == $HIGH_VALUE_STRING && $new_tag == $HIGH_VALUE_STRING) { + break; + } + $matches = array(); + $old_star = false; + if (preg_match("/(.*)(\*)$/", $old_tag, $matches)) { + $old_star = true; + $old_tag = $matches[1]; + } + $new_star = false; + if (preg_match("/(.*)(\*)$/", $new_tag, $matches)) { + $new_star = true; + $new_tag = $matches[1]; + } + if ($old_tag > $new_tag) { + // Its missing in the old list so add it + $this->_add_tag($new_tag, $itemids); + $new_index++; + } else if ($old_tag < $new_tag) { + // Its missing in the new list so its been removed + $this->_delete_tag($old_tag, $itemids); + $old_index++; + } else { + if ($old_star && !$new_star) { + // User wants tag to apply to all items, originally only on some of selected + $this->_update_tag($old_tag, $itemids); + } // Not changed ignore + $old_index++; + $new_index++; + } + } + } + print json_encode(array("form" => $form->__toString(), "message" => t("Tags updated"))); } + public function reset_edit_tags() { + $itemids = $this->input->get("item"); + + print organize::get_tag_form($itemids); + } + + private function _add_tag($new_tag, $itemids) { + // Super lame security stopgap. This code is going to get rewritten anyway. + foreach ($itemids as $item_id) { + $item = ORM::factory("item", $item_id); + access::required("view", $item); + access::required("edit", $item); + } + $tag = ORM::factory("tag") + ->where("name", $new_tag) + ->find(); + if ($tag->loaded) { + $tag->count += count($itemids); + } else { + $tag->name = $new_tag; + $tag->count = count($itemids); + } + $tag->save(); + + $db = Database::instance(); + foreach ($itemids as $item_id) { + $db->query("INSERT INTO {items_tags} SET item_id = $item_id, tag_id = {$tag->id};"); + } + } + + private function _delete_tag($new_tag, $itemids) { + // Super lame security stopgap. This code is going to get rewritten anyway. + foreach ($itemids as $item_id) { + $item = ORM::factory("item", $item_id); + access::required("view", $item); + access::required("edit", $item); + } + + $tag = ORM::factory("tag") + ->where("name", $new_tag) + ->find(); + $tag->count -= count($itemids); + if ($tag->count > 0) { + $tag->save(); + } else { + $tag->delete(); + } + + $ids = implode(", ", $itemids); + Database::instance()->query( + "DELETE FROM {items_tags} WHERE tag_id = {$tag->id} AND item_id IN ($ids);"); + } + + private function _update_tag($new_tag, $itemids) { + // Super lame security stopgap. This code is going to get rewritten anyway. + foreach ($itemids as $item_id) { + $item = ORM::factory("item", $item_id); + access::required("view", $item); + access::required("edit", $item); + } + + $tag = ORM::factory("tag") + ->where("name", $new_tag) + ->find(); + + $db = Database::instance(); + $ids = implode(", ", $itemids); + $result = $db->query( + "SELECT item_id FROM {items_tags} + WHERE tag_id = {$tag->id} + AND item_id IN ($ids)"); + + $add_items = array_fill_keys($itemids, 1); + foreach($result as $row) { + unset($add_items[$row->item_id]); + } + $add_items = array_keys($add_items); + $tag->count += count($add_items); + $tag->save(); + foreach ($add_items as $item_id) { + $db->query("INSERT INTO {items_tags} SET item_id = $item_id, tag_id = {$tag->id};"); + } + } + + private function _getOperationDefinition($item, $operation) { + switch ($operation) { + case "move": + return array("description" => + t("Move albums and photos to '%name'", array("name" => $item->title)), + "name" => t("Move to '%name'", array("name" => $item->title)), + "type" => "move", + "runningMsg" => t("Move in progress"), + "pauseMsg" => t("The move operation was paused"), + "resumeMsg" => t("The move operation was resumed")); + break; + + case "rearrange": + return array("description" => t("Rearrange the order of albums and photos"), + "name" => t("Rearrange: %name", array("name" => $item->title)), + "type" => "rearrange", + "runningMsg" => t("Rearrange in progress"), + "pauseMsg" => t("The rearrange operation was paused"), + "resumeMsg" => t("The rearrange operation was resumed")); + break; + + case "rotateCcw": + return array("description" => t("Rotate the selected photos counter clockwise"), + "name" => t("Rotate images in %name", array("name" => $item->title)), + "type" => "rotateCcw", + "runningMsg" => t("Rotate Counter Clockwise in progress"), + "pauseMsg" => t("The rotate operation was paused"), + "resumeMsg" => t("The rotate operation was resumed")); + break; + + case "rotateCw": + return array("description" => t("Rotate the selected photos clockwise"), + "name" => t("Rotate images in %name", array("name" => $item->title)), + "type" => "rotateCw", + "runningMsg" => t("Rotate Clockwise in progress"), + "pauseMsg" => t("The rotate operation was paused"), + "resumeMsg" => t("The rotate operation was resumed")); + break; + + case "delete": + return array("description" => t("Delete selected photos / albums"), + "name" => t("Delete images in %name", array("name" => $item->title)), + "type" => "delete", + "runningMsg" => t("Delete images in progress"), + "pauseMsg" => t("The delete operation was paused"), + "resumeMsg" => t("The delete operation was resumed")); + break; + + case "albumCover": + return array("description" => t("Reset Album Cover"), + "name" => t("Reset Album cover for %name", array("name" => $item->title)), + "type" => "albumCover", + "runningMsg" => t("Reset Album Cover in progress"), + "pauseMsg" => t("Reset album cover was paused"), + "resumeMsg" => t("Reset album cover was resumed")); + break; + + default: + throw new Exception("Operation '$operation' is not implmented"); + } + } } diff --git a/modules/organize/css/organize.css b/modules/organize/css/organize.css index 4568a707..e58cd5a5 100644 --- a/modules/organize/css/organize.css +++ b/modules/organize/css/organize.css @@ -1,44 +1,41 @@ +/* @todo move to theme css */ /******************************************************************* * Dialog wide stylings */ -#gOrganizeDialog { - text-align: left; -} - -#gOrganize { - overflow: hidden; +#gMessage { + margin-bottom: .4em; } -#gOrganize .yui-u { - width: 75%; +#gMessage .gInfo { + background-color: transparent; + background-image: none; + padding-left: .4em; } -#gOrganize .yui-gf .first { - width: 25%; +#gOrganizeProgressDialog { + text-align: left; } -#gOrganize .yui-gf #gMessage { - margin-bottom: .4em; - width: 75%; +#gDialog .yui-gf div.first { + width: 20%; } -#gMessage .gInfo { - font-weight: bold; - padding-left: 2em; +#gDialog .yui-gf .yui-u { + width: 80%; } - /******************************************************************* * Album Tree styling */ #gOrganizeTreeContainer { - overflow: auto; + overflow-y: auto; margin: 0 !important; padding: 0 !important; } -#gOrganizeTreeContainer ul ul li { - padding-left: 1.2em; +#gOrganizeAlbumDescription { + height: 2em; + overflow-y: auto; } .gBranchSelected { @@ -48,21 +45,37 @@ padding: .3em 0; } +.gBranchDroppable { + border: 1px dotted; +} + +.gBranchText { + cursor: pointer; + width: auto; +} + .gBranchCollapsed { display: none; } -.gOrganizeBranch span { - cursor: pointer; +.gBranchEmpty { + visibility: hidden; } -.gBranchText { - cursor: pointer; - width: auto; +#gOrganizeTreeContainer ul ul li { + padding-left: 1.2em; } + /******************************************************************* * Album Panel Styles */ + +#gMicroThumbUnselectAll, +#gMicroThumbSelectAll { + font-size: 1em; + font-weight: bold; +} + #gMicroThumbPanel { margin: 0 !important; padding: 0 !important; @@ -70,27 +83,33 @@ border: 1px solid #999 !important; border-top: none !important; border-left: none !important; + margin-left: -1em !important; overflow-x: hidden; overflow-y: auto; } #gMicroThumbGrid { + padding: .5em; } .gMicroThumbContainer { -// padding: 0 .5em; -// opacity: .4; -} - -.gMicroThumb { display: block; float: left; -// font-size: .7em; + font-size: .7em; height: 9em; margin-bottom: 1em; margin-left: 1em; - text-align: center; + opacity: .4; + padding: 0 .5em; +} + +.gMicroThumb { + height: 9em; width: 9em; + background-color: #fff; + display: block; + float: left; + text-align: center; } #gMicroThumbPanel #gMicroThumbGrid .gAlbum { @@ -101,12 +120,35 @@ opacity: 1; } +.gMicroThumbContainer.ui-selected { + opacity: 1; +} + +#gDragHelper .gMicroThumbGrid { + background-color: transparent; + padding: 0; + overflow: visible; +} + +#gDragHelper .gMicroThumbContainer { + display: block; + margin: 0; + padding: 0; +} + +#gDragHelper .gMicroThumb { + background-color: transparent; + height: auto; + width: auto; +} + + /**************************************************************** * Organize Edit Drawer styling */ #gOrganizeEditDrawer { background-color: #13A; - width: 100% !important; + width: 90%; } #gOrganizeEditDrawerPanel { @@ -162,3 +204,79 @@ height: 30px; width: 15px; } + +#gOrganizeFormButtons { + bottom: 0.5em; +} + +#gOrganizeFormButtons .submit { + display: inline; + float: none; + left: 0.5em; + position: relative; +} + +/* yui-u gives 80% width, but then we wrap so do it ourselves */ +#gOrganizeEditForm { + float: right; + width: 79%; + // height: 100px; +} + +#gOrganizeFormThumbs { + overflow: hidden; +} + +#gOrganizeFormThumbs div { + margin: 0; + text-align: center; + background: transparent none repeat scroll 0 0; +} + +#gOrganizeFormThumbs .gMicroThumbContainer { + display: block; + float: left; + opacity: 1; + position: absolute; +} + +/**************************************************************** + * Organize Edit From tabs styling + */ +#gOrganizeEditForm.ui-tabs .ui-tabs-hide { + display: block !important; + left: -10000px; + position: absolute; +} + +#gOrganizeEditForm.ui-widget { + font-size: .75em; +} + +.gOrganizeEditPane { + height: 135px; + overflow-y: auto; +} + +.textbox, +.textarea { + border: 1px solid #e8e8e8; + border-top-color: #ccc; + border-left-color: #ccc; + color: #333; + width: 100%; +} + +.textarea { + height: 6em; +} + +.textbox { + height: 1.3em; + width: 50% +} + +.gTagGroup { + float:left; + margin: .5em; +} diff --git a/modules/organize/helpers/organize_task.php b/modules/organize/helpers/organize_task.php new file mode 100644 index 00000000..dc474818 --- /dev/null +++ b/modules/organize/helpers/organize_task.php @@ -0,0 +1,131 @@ +context); + $taskType = $context["type"]; + + try { + $target = ORM::factory("item", $context["target"]); + $total = count($context["items"]); + $stop = min($total - $context["position"], $context["batch"]); + $context["post_process"] = array(); + for ($offset = 0; $offset < $stop; $offset++) { + $current_id = $context["position"] + $offset; + $id = $context["items"][$current_id]; + switch ($taskType) { + case "move": + $source = ORM::factory("item", $id); + access::required("view", $source); + access::required("view", $target); + access::required("edit", $source); + access::required("edit", $target); + + item::move($source, $target); + break; + + case "rearrange": + $item = ORM::factory("item", $id); + access::required("view", $item); + access::required("edit", $item); + + Database::instance() + ->query("Update {items} set weight = {$context["position"]} where id=$id;"); + break; + + case "rotateCcw": + case "rotateCw": + $item = ORM::factory("item", $id); + access::required("view", $item); + access::required("edit", $item); + + if ($item->is_photo()) { + $context["post_process"]["reload"][] = + self::_do_rotation($item, $taskType == "rotateCcw" ? -90 : 90); + } + break; + + case "albumCover": + $item = ORM::factory("item", $id); + access::required("view", $item); + access::required("view", $item->parent()); + access::required("edit", $item->parent()); + + item::make_album_cover($item); + break; + + case "delete": + $item = ORM::factory("item", $id); + access::required("view", $item); + access::required("edit", $item); + + $item->delete(); + $context["post_process"]["remove"][] = array("id" => $id); + break; + + default: + throw new Exception("Task '$taskType' is not implemented"); + } + } + $context["position"] += $stop; + $task->state = "success"; + } catch(Exception $e) { + $task->status = $e->getMessage(); + $task->state = "error"; + $task->save(); + throw $e; + } + $task->context = serialize($context); + $total = count($context["items"]); + $task->percent_complete = $context["position"] / (float)$total * 100; + $task->done = $context["position"] == $total || $task->state == "error"; + } + + private static function _do_rotation($item, $degrees) { + // This code is copied from Quick_Controller::rotate + graphics::rotate($item->file_path(), $item->file_path(), array("degrees" => $degrees)); + + list($item->width, $item->height) = getimagesize($item->file_path()); + $item->resize_dirty= 1; + $item->thumb_dirty= 1; + $item->save(); + + graphics::generate($item); + + $parent = $item->parent(); + if ($parent->album_cover_item_id == $item->id) { + copy($item->thumb_path(), $parent->thumb_path()); + $parent->thumb_width = $item->thumb_width; + $parent->thumb_height = $item->thumb_height; + $parent->save(); + } + list ($height, $width) = $item->scale_dimensions(90); + $margin_top = (90 - $height) / 20; + + return array("src" => $item->thumb_url() . "?rnd=" . rand(), + "id" => $item->id, + "marginTop" => "{$margin_top}em", "width" => $width, "height" => $height); + } +} \ No newline at end of file diff --git a/modules/organize/helpers/organize_theme.php b/modules/organize/helpers/organize_theme.php index f01ab88b..e4feba2b 100644 --- a/modules/organize/helpers/organize_theme.php +++ b/modules/organize/helpers/organize_theme.php @@ -19,7 +19,8 @@ */ class organize_theme { static function head($theme) { - //$theme->script("organize_init.js"); + // @tdo remove the addition css and organize.js (just here to test) + $theme->script("organize_init.js"); $theme->script("organize.js"); $theme->css("organize.css"); } diff --git a/modules/organize/js/organize.js b/modules/organize/js/organize.js index e84afd03..12d8a5b5 100644 --- a/modules/organize/js/organize.js +++ b/modules/organize/js/organize.js @@ -1,116 +1,621 @@ -(function($) { - $.fn.organize = function(options) { - var size = $.getViewportSize(); - var height = size.height() - 100; // Leave 50 pixels on the top and bottom of the dialog - var width = size.width() - 100; // Leave 50 pixels on the left and right of the dialog - var opts = $.extend({}, $.fn.organize.defaults, {width: width, height: height}, options); - return this.each(function() { - $(this).click(function(event) { - var href = event.target.href; - var size = $.getViewportSize(); - - $("body").append('
          '); - - $("#gOrganizeDialog").dialog(opts); - // Pass the approx height and width of the thumb grid to optimize thumb retrieval - $.get(href, _init); - return false; +/* + * @todo Trap resize of dialog and resize the child areas (tree, grid and edit form) + */ +var url; +var paused = false; +var task = null; +var transitItems = []; +var heightMicroThumbPanel; + +// ************************************************************************** +// JQuery UI Widgets +// Draggable +var draggable = { + handle: ".gMicroThumbContainer.ui-selected", + revert: true, + zindex: 2000, + distance: 10, + helper: function(event, ui) { + if (!$(event.currentTarget).hasClass("ui-selected")) { + $(event.currentTarget).addClass("ui-selected"); + setDrawerButtonState(); + } + $("#gMicroThumbPanel").append("
            "); + var beginTop = event.pageY; + var beginLeft = event.pageX; + var zindex = $(".gMicroThumbContainer").draggable("option", "zindex"); + $("#gDragHelper").css('top', event.pageY - 22.5); + $("#gDragHelper").css('left', event.pageX + 22.5); + var placeHolder = $(this).clone(); + $(placeHolder).attr("id", "gPlaceHolder"); + $(placeHolder).css("visibility", "hidden"); + $(placeHolder).removeClass("ui-selected"); + $(placeHolder).removeClass("ui-draggable"); + $(this).after(placeHolder); + + $("li.ui-selected").each(function(i) { + var clone = $(this).clone(); + $(clone).attr("id", "drag_clone_" + $(this).attr("ref")); + $("#gDragHelper ul").append(clone); + $(clone).css("position", "absolute"); + $(clone).css("top", beginTop); + $(clone).css("left", beginLeft); + $(clone).css("z-index", zindex--); + $(this).hide(); + + var children = $(clone).find(".gMicroThumb .gThumbnail"); + var width = new String(children.css("width")).replace(/[^0-9]/g,"") * .5; + var height = new String(children.css("height")).replace(/[^0-9]/g,"") * .5; + var marginTop = new String(children.css("margin-top")).replace(/[^\.0-9]/g,"") * .5; + children.attr("width", width); + children.attr("height", height); + children.css("margin-top", marginTop); + if (i < 9) { + beginTop -= 5; + beginLeft += 5; + } + }); + return $("#gDragHelper"); + }, + stop: function(event, ui) { + $("#gDragHelper li").each(function(i) { + $("#thumb_" + $(this).attr("ref")).show(); + }); + $(".gMicroThumbContainer.ui-selected").css("z-index", null); + $("#gDragHelper").remove(); + $("#gPlaceHolder").remove(); + } +}; + +// Thumbnail Grid Droppable +var thumbDroppable = { + tolerance: "pointer", + over: function(event, ui) { + $("#gPlaceHolder").show(); + }, + out: function(event, ui) { + $("#gPlaceHolder").hide(); + }, + drop: function(event, ui) { + $("#gDragHelper").hide(); + $("#gPlaceHolder").hide(); + var newOrder = ""; + $("#gMicroThumbGrid .gMicroThumbContainer").each(function(i) { + if ($(this).attr("id") == "gPlaceHolder") { + $("#gDragHelper li").each(function(i) { + newOrder += "&item[]=" + $(this).attr("ref"); + }); + } else if ($(this).css("display") != "none") { + newOrder += "&item[]=" + $(this).attr("ref"); + } else { + // If its not displayed then its one of the ones being moved so ignore. + } + }); + $("#gDragHelper li").each(function(i) { + $("#gPlaceHolder").before($("#thumb_" + $(this).attr("ref")).show()); + }); + $.ajax({ + data: newOrder, + dataType: "json", + success: operationCallback, + type: "POST", + url: get_organize_url("organize/startTask/rearrange", {item_id: item_id}) + }); + } +}; + +// Album Tree Droppable +var treeDroppable = { + tolerance: "pointer", + greedy: true, + hoverClass: "gBranchDroppable", + drop: function(event, ui) { + $("#gDragHelper").hide(); + var targetItemId = $(this).attr("ref"); + if ($(this).hasClass("gBranchSelected")) { + $("#gMessage").empty().append(INVALID_DROP_TARGET); + ui.draggable.trigger("stop", event); + return false; + } + var postData = serializeItemIds("#gDragHelper li"); + var okToMove = true; + $("#gDragHelper li").each(function(i) { + okToMove &= targetItemId != $(this).attr("ref"); + }); + if (!okToMove) { + $("#gMessage").empty().append(INVALID_DROP_TARGET); + ui.draggable.trigger("stop", event); + return false; + } + $("#gDragHelper li").each(function(i) { + $("#thumb_" + $(this).attr("ref")).remove(); + }); + $.ajax({ + data: postData, + dataType: "json", + success: operationCallback, + type: "POST", + url: get_organize_url("organize/startTask/move", {item_id: targetItemId}) + }); + return true; + } +}; + +// Selectable +var selectable = { + filter: ".gMicroThumbContainer", + selected: function(event, ui) { + setDrawerButtonState(); + }, + unselected: function(event, ui) { + setDrawerButtonState(); + }, + stop: function(event, ui) { + getEditForm(); + } +}; + +// ************************************************************************** +// Event Handlers +// MicroThumbContainer mouseup +var onMicroThumbContainerMouseup = function(event) { + // For simplicity always remove the ui-selected class. If it was unselected + // it will get added back + $(this).toggleClass("ui-selected"); + + setDrawerButtonState(); + if ($("#gMicroThumbGrid li.ui-selected").length > 0) { + getEditForm(); + } +}; + +// MicroThumbContainer mousemove +var onMicroThumbContainerMousemove = function(event) { + if ($("#gDragHelper").length > 0 && $(this).attr("id") != "gPlaceHolder") { + if (event.pageX < $(this).offset().left + $(this).width() / 2) { + $(this).before($("#gPlaceHolder")); + } else { + $(this).after($("#gPlaceHolder")); + } + var container = $("#gMicroThumbPanel").get(0); + var scrollHeight = container.scrollHeight; + var scrollTop = container.scrollTop; + var height = $(container).height(); + if (event.pageY > height + scrollTop) { + container.scrollTop = this.offsetTop; + } else if (event.pageY < scrollTop) { + container.scrollTop -= height; + } + } +}; + +// Handle click events on the buttons on the drawer handle +function drawerHandleButtonsClick(event) { + event.preventDefault(); + if (!$(this).attr("disabled")) { + var operation = $(this).attr("ref"); + switch (operation) { + case "edit": + case "close": + $("#gOrganizeEditDrawerPanel").animate( + {"height": "toggle", "display": "block"}, + {duration: "fast", + complete: function() { + setSelectedThumbs(); + if (operation == "close") { + $("#gOrganizeEditHandleButtonsLeft a[ref='edit']").css("display", "inline-block"); + $("#gOrganizeEditHandleButtonsLeft a[ref='close']").css("display", "none"); + $("#gOrganizeEditHandleButtonsMiddle a").css("display", "none"); + } else { + $("#gOrganizeEditHandleButtonsLeft a[ref='edit']").css("display", "none"); + $("#gOrganizeEditHandleButtonsLeft a[ref='close']").css("display", "inline-block"); + $("#gOrganizeEditHandleButtonsMiddle a").css("display", "inline-block"); + } + }, + step: function() { + $("#gMicroThumbPanel").height(heightMicroThumbPanel - $(this).height()); + } + }); + break; + case "select-all": + $("#gMicroThumbGrid li").addClass("ui-selected"); + $("#gMicroThumbSelectAll").hide(); + $("#gMicroThumbUnselectAll").show(); + setDrawerButtonState(); + getEditForm(); + break; + case "unselect-all": + $("#gMicroThumbGrid li").removeClass("ui-selected"); + $("#gMicroThumbSelectAll").show(); + $("#gMicroThumbUnselectAll").hide(); + setDrawerButtonState(); + break; + case "done": + $("#gDialog").dialog("close"); + break; + case "submit": + var currentTab = $("#gOrganizeEditForm").tabs("option", "selected"); + var form = $("#pane-"+currentTab+" form"); + var url = $(form).attr("action") + .replace("__FUNCTION__", $(form).attr("ref")); + $.ajax({ + data: $(form).serialize(), + dataType: "json", + success: function (data, textStatus) { + $("#pane-"+currentTab).children("form").replaceWith(data.form); + if (data.message) { + $("#gMessage").empty().append("
            " + data.message + "
            "); + } + }, + type: "POST", + url: url + }); + break; + case "reset": + currentTab = $("#gOrganizeEditForm").tabs("option", "selected"); + form = $("#pane-"+currentTab+" form"); + $.ajax({ + data: serializeItemIds("#gMicroThumbPanel li.ui-selected"), + dataType: "html", + success: function (data, textStatus) { + $("#pane-"+currentTab + " form").replaceWith(data); + }, + type: "GET", + url: $(form).attr("action").replace("__FUNCTION__", "reset_" + $(form).attr("ref")) }); + break; + case "delete": + if (!confirm(CONFIRM_DELETE)) { + break; + } + default: + $.ajax({ + data: serializeItemIds("#gMicroThumbPanel li.ui-selected"), + dataType: "json", + success: operationCallback, + type: "POST", + url: get_organize_url("organize/startTask/" + operation, {item_id: item_id}) + }); + break; + } + } +}; + +// ************************************************************************** +// AJAX Callbacks +// MicroThumbContainer click +var getMicroThumbsCallback = function(json, textStatus) { + if (json.count > 0) { + $("#gMicroThumbGrid").append(json.data); + retrieveMicroThumbs(); + $(".gMicroThumbContainer").mouseup(onMicroThumbContainerMouseup); + $(".gMicroThumbContainer").mousemove(onMicroThumbContainerMousemove); + $(".gMicroThumbContainer").draggable(draggable); + } +}; + +var operationCallback = function (data, textStatus) { + var done = false; + if (!paused) { + createProgressDialog(data.runningMsg); + task = data.task; + task.pauseMsg = data.pauseMsg; + task.resumeMsg = data.resumeMsg; + done = data.task.done; + } + $(".gMicroThumbContainer").draggable("disable"); + paused = false; + while (!done && !paused) { + $.ajax({async: false, + success: function(data, textStatus) { + $(".gProgressBar").progressbar("value", data.task.percent_complete); + done = data.task.done; + if (data.task.post_process.reload) { + $.each(data.task.post_process.reload, function() { + var selector = "#gMicroThumb-" + this.id + " img"; + $(selector).attr("height", this.height); + $(selector).attr("width", this.width); + $(selector).attr("src", this.src); + $(selector).css("margin-top", this.marginTop); + }); + } + if (data.task.post_process.remove) { + $.each(data.task.post_process.remove, function() { + $("#thumb_" + this.id).remove(); + }); + } + }, + error: function(XMLHttpRequest, textStatus, errorThrown) { + paused = true; + displayAjaxError(XMLHttpRequest.responseText); + }, + dataType: "json", + type: "POST", + url: get_organize_url("organize/runTask", {task_id: task.id}) }); - }; + } + if (!paused) { + $("#gOrganizeProgressDialog").dialog("destroy").remove(); + $.ajax({async: false, + success: function(data, textStatus) { + setDrawerButtonState(); + task = null; + $("#gMessage").empty().append("
            " + data.task.status + "
            "); + }, + dataType: "json", + type: "POST", + url: get_organize_url("organize/finishTask", {task_id: task.id}) + }); + } + $(".gMicroThumbContainer").draggable("enable"); +}; - $.fn.organize.defaults = { - autoOpen: false, - modal: true, - resizable: false, - minWidth: 600, - minHeight: 500, - position: "center", - close: function () { - $("#gOrganizeDialog").trigger("organize_close"); - $("#gOrganizeDialog").dialog("destroy").remove(); - }, - zIndex: 75 - }; +// ************************************************************************** + +/** + * Dynamically initialize the organize dialog when it is displayed + */ +function organize_dialog_init() { + var size = getViewportSize(); + heightMicroThumbPanel = size.height() - 100; + var width = size.width() - 100; + + // Deal with ui.jquery bug: http://dev.jqueryui.com/ticket/4475 + $(".sf-menu li.sfHover ul").css("z-index", 70); + + $("#gDialog").dialog("option", "width", width); + $("#gDialog").dialog("option", "height", heightMicroThumbPanel); + + $("#gDialog").dialog("open"); + if ($("#gDialog h1").length) { + $("#gDialog").dialog('option', 'title', $("#gDialog h1:eq(0)").html()); + } else if ($("#gDialog fieldset legend").length) { + $("#gDialog").dialog('option', 'title', $("#gDialog fieldset legend:eq(0)").html()); + } + + $("#gDialog").bind("organize_close", function(target) { + $.gallery_reload(); + }); + + heightMicroThumbPanel -= 2 * parseFloat($("#gDialog").css("padding-top")); + heightMicroThumbPanel -= 2 * parseFloat($("#gDialog").css("padding-bottom")); + heightMicroThumbPanel -= $("#gMicroThumbPanel").position().top; + heightMicroThumbPanel -= $("#gDialog #ft").height(); + heightMicroThumbPanel -= $("#gOrganizeEditDrawerHandle").height(); + heightMicroThumbPanel = Math.round(heightMicroThumbPanel); + + $("#gMicroThumbPanel").height(heightMicroThumbPanel); + $("#gOrganizeTreeContainer").height(heightMicroThumbPanel); + + $(".gOrganizeBranch .ui-icon").click(organizeToggleChildren); + $(".gBranchText").droppable(treeDroppable); + $(".gBranchText").click(organizeOpenFolder); + retrieveMicroThumbs(item_id); + //showLoading("#gDialog"); - /** - * Dynamically initialize the organize dialog when it is displayed - */ - function _init(data) { + $("#gMicroThumbPanel").droppable(thumbDroppable); + $("#gMicroThumbPanel").selectable(selectable); + $("#gOrganizeEditDrawerHandle a").click(drawerHandleButtonsClick); +} - // Deal with ui.jquery bug: http://dev.jqueryui.com/ticket/4475 - $(".sf-menu li.sfHover ul").css("z-index", 70); +function retrieveMicroThumbs() { + var offset = $("#gMicroThumbGrid li").length; + if (url == null) { + var grid_width = $("#gMicroThumbPanel").width(); + url = $("#gMicroThumbPanel").attr("ref"); + url = url.replace("__WIDTH__", grid_width); + url = url.replace("__HEIGHT__", heightMicroThumbPanel); + } + var url_data = url.replace("__OFFSET__", offset); + url_data = url_data.replace("__ITEM_ID__", item_id); + $.getJSON(url_data, getMicroThumbsCallback); +} - $("#gOrganizeDialog").html(data); - $("#gOrganizeDialog").dialog("open"); +function organizeToggleChildren(event) { + var id = $(this).attr("ref"); + var span_children = $("#gOrganizeChildren-" + id); + if ($(this).hasClass("ui-icon-plus")) { + $(this).removeClass("ui-icon-plus"); + $(this).addClass("ui-icon-minus"); + $("#gOrganizeChildren-" + id).removeClass("gBranchCollapsed"); + } else { + $(this).removeClass("ui-icon-minus"); + $(this).addClass("ui-icon-plus"); + $("#gOrganizeChildren-" + id).addClass("gBranchCollapsed"); + } + event.preventDefault(); +} - var heightMicroThumbPanel = $("#gOrganizeDialog").innerHeight(); - heightMicroThumbPanel -= 2 * parseFloat($("#gOrganizeDialog").css("padding-bottom")); - heightMicroThumbPanel -= $("#gMessage").outerHeight(); - heightMicroThumbPanel = Math.floor(heightMicroThumbPanel); - $("#gOrganizeTreeContainer").height(heightMicroThumbPanel); +function organizeOpenFolder(event) { + var selected = $(".gBranchSelected"); + if ($(selected).attr("id") != $(this).attr("id")) { + $(selected).removeClass("gBranchSelected"); + $(this).addClass("gBranchSelected"); + item_id = $(this).attr("ref"); + $("#gMicroThumbGrid").empty(); + retrieveMicroThumbs(); + } + event.preventDefault(); +} - heightMicroThumbPanel -= $("#gOrganizeEditDrawerHandle").outerHeight(); - $("#gMicroThumbPanel").height(heightMicroThumbPanel); +function get_organize_url(uri, parms) { + var url = rearrangeUrl; + url = url.replace("__URI__", uri); + url = url.replace("__ITEM_ID__", !parms.item_id ? "" : parms.item_id); + url += (parms.item_id && parms.task_id) ? "/" : ""; + url = url.replace("__TASK_ID__", !parms.task_id ? "" : parms.task_id); + return url; +} - if ($("#gOrganizeDialog h1").length) { - $("#gOrganizeDialog").dialog('option', 'title', $("#gOrganizeDialog h1:eq(0)").html()); - } else if ($("#gOrganizeDialog fieldset legend").length) { - $("#gOrganizeDialog").dialog('option', 'title', $("#gOrganizeDialog fieldset legend:eq(0)").html()); +/** + * Set the enabled/disabled state of the buttons. The album cover is only enabled if + * there is only 1 image selected + */ +function setDrawerButtonState() { + $("#gOrganizeFormThumbStack").empty(); + $("#gOrganizeEditForm").empty(); + var selectedCount = $("#gMicroThumbGrid li.ui-selected").length; + if (selectedCount) { + $("#gOrganizeEditHandleButtonsLeft a").removeAttr("disabled"); + $("#gOrganizeEditHandleButtonsLeft a").removeClass("ui-state-disabled"); + + if (selectedCount > 1) { + $("#gOrganizeEditHandleButtonsLeft a[ref='albumCover']").attr("disabled", true); + $("#gOrganizeEditHandleButtonsLeft a[ref='albumCover']").addClass("ui-state-disabled"); + } + setSelectedThumbs(); + } else { + if ($("#gOrganizeEditDrawerPanel::visible").length) { + $("#gOrganizeEditHandleButtonsLeft a[ref='close']").trigger("click"); } + $("#gOrganizeEditHandleButtonsLeft a").attr("disabled", true); + $("#gOrganizeEditHandleButtonsLeft a").addClass("ui-state-disabled"); + } +} - $("#gOrganizeDialog #gMicroThumbDone").click(_dialog_close); - $("#gOrganizeDialog").bind("organize_close", function(target) { - $.gallery_reload(); +function setSelectedThumbs() { + if (!$("#gOrganizeEditDrawerPanel::visible").length) { + return; + } + var position = $("#gOrganizeFormThumbStack").position(); + var beginLeft = position.left; + var beginTop = 50; + var zindex = 2000; + $("li.ui-selected").each(function(i) { + var clone = $(this).clone(); + $(clone).attr("id", "edit_clone_" + $(this).attr("ref")); + $("#gOrganizeFormThumbStack").append(clone); + $(clone).removeClass("ui-draggable"); + $(clone).removeClass("ui-selected"); + $(clone).css("margin-top", beginTop); + $(clone).css("left", beginLeft); + $(clone).css("z-index", zindex--); + + if (i < 9) { + beginTop -= 5; + beginLeft += 5; + } + }); +} + +function getEditForm() { + if ($("#gMicroThumbGrid li.ui-selected").length > 0) { + var postData = serializeItemIds("li.ui-selected"); + var url_data = get_organize_url("organize/editForm", {}) + postData; + $.get(url_data, function(data, textStatus) { + $("#gOrganizeEditForm").tabs("destroy"); + $("#gOrganizeEditForm").html(data); + if ($("#gOrganizeEditForm ul li").length) { + $("#gOrganizeEditForm").tabs(); + $("#gOrganizeEditHandleButtonsMiddle a").removeAttr("disabled"); + $("#gOrganizeEditHandleButtonsMiddle a").removeClass("ui-state-disabled"); + } else { + $("#gOrganizeEditHandleButtonsMiddle a").attr("disabled", true); + $("#gOrganizeEditHandleButtonsMiddle a").addClass("ui-state-disabled"); + } }); + } else { + $("#gOrganizeEditForm").tabs("destroy"); + $("#gOrganizeEditForm").empty(); + } +} - //$(".gOrganizeBranch .ui-icon").click(organizeToggleChildren); - //$(".gBranchText").droppable(treeDroppable); - //$(".gBranchText").click(organizeOpenFolder); - //retrieveMicroThumbs(item_id); - //showLoading("#gOrganizeDialog"); +function serializeItemIds(selector) { + var postData = ""; + $(selector).each(function(i) { + postData += "&item[]=" + $(this).attr("ref"); + }); - //$("#gMicroThumbPanel").droppable(thumbDroppable); - //$("#gMicroThumbPanel").selectable(selectable); - //$("#gOrganizeEditDrawerHandle a").click(drawerHandleButtonsClick); + return postData; +} - $(window).bind("resize", _size_dialog); - }; +function submitCurrentForm(event) { + console.log("submitCurrentForm"); + return false; +} - /** - * Dynamically initialize the organize dialog when it is displayed - */ - function _size_dialog(event) { - var size = $.getViewportSize(); - var h = $("#gOrganizeDialog").dialog("option", "minHeight"); - var sh = size.height() - 100; - var height = Math.max(sh, h); - var w = $("#gOrganizeDialog").dialog("option", "minWidth"); - var sw = size.width() - 100; - var width = Math.max(w, sw); - - $("#gOrganizeDialog").parent().css("height", height); - $("#gOrganizeDialog").parent().css("width", width); - $("#gOrganizeDialog").parent().css("left", "50px"); - $("#gOrganizeDialog").parent().css("top", "50px"); - - var heightMicroThumbPanel = height - 50; - heightMicroThumbPanel -= 2 * parseFloat($("#gOrganizeDialog").css("padding-bottom")); - heightMicroThumbPanel -= $("#gMessage").outerHeight(); - heightMicroThumbPanel = Math.floor(heightMicroThumbPanel); - $("#gOrganizeTreeContainer").height(heightMicroThumbPanel); - - heightMicroThumbPanel -= $("#gOrganizeEditDrawerHandle").outerHeight(); - $("#gMicroThumbPanel").height(heightMicroThumbPanel); - }; +function resetCurrentForm(event) { + console.log("resetCurrentForm"); + return false; +} - function _dialog_close(event) { - event.preventDefault(); - $("#gOrganizeDialog").dialog("close"); +function createProgressDialog(title) { + $("body").append("
            " + + "
            " + + "" + + "" + + "" + + "
            "); + $("#gOrganizeProgressDialog").dialog({ + autoOpen: true, + autoResize: false, + modal: true, + resizable: false, + title: title + }); + + $(".gProgressBar").progressbar(); + $("#gOrganizeTaskPause").click(function(event) { + paused = true; + $("#gOrganizeTaskPause").hide(); + $("#gOrganizeTaskResume").show(); + $("#gOrganizeTaskCancel").show(); + $("#gMessage").empty().append(task.pauseMsg); + }); + $("#gOrganizeTaskResume").click(function(event) { + $("#gOrganizeTaskPause").show(); + $("#gOrganizeTaskResume").hide(); + $("#gOrganizeTaskCancel").hide(); + $("#gMessage").empty().append(task.resumeMsg); + operationCallback(); + //startRearrangeCallback(); + }); + $("#gOrganizeTaskCancel").click(function(event) { + $("#gOrganizeTaskPause").show(); + $("#gOrganizeTaskResume").hide(); + $("#gOrganizeTaskCancel").hide(); + + $.ajax({async: false, + success: function(data, textStatus) { + task = null; + paused = false; + transitItems = []; + $("#gMessage").empty().append("
            " + data.task.status + "
            "); + $("#gOrganizeProgressDialog").dialog("destroy").remove(); + }, + dataType: "json", + type: "POST", + url: get_organize_url("organize/cancelTask", {task_id: task.id}) + }); + }); +} + +// ************************************************************************** +// Functions that should probably be in a gallery namespace +function getViewportSize() { + return { + width : function() { + return window.innerWidth + || document.documentElement && document.documentElement.clientWidth + || document.body.clientWidth; + }, + height : function() { + return window.innerHeight + || document.documentElement && document.documentElement.clientHeight + || document.body.clientHeight; + } }; +} -})(jQuery); +function displayAjaxError(error) { + $("body").append("
            " + error + "
            "); -$("document").ready(function() { - $("#gOrganizeLink").organize(); -}); + $("#gAjaxError").dialog({ + autoOpen: true, + autoResize: false, + modal: true, + resizable: true, + width: 610, + height: $("#gDialog").height() + }); +} diff --git a/modules/organize/js/organize_init.js b/modules/organize/js/organize_init.js new file mode 100644 index 00000000..ed036fdb --- /dev/null +++ b/modules/organize/js/organize_init.js @@ -0,0 +1,29 @@ +$("document").ready(function() { + $("#gOrganizeLink").click(function(event) { + event.preventDefault(); + var href = event.target.href; + + $("body").append('
            '); + + $("#gDialog").dialog({ + autoOpen: false, + autoResize: false, + modal: true, + resizable: false, + close: function () { + $("#gDialog").trigger("organize_close"); + $("#gDialog").dialog("destroy").remove(); + }, + zIndex: 75 + }); + + //showLoading("#gDialog"); + + $.get(href, function(data) { + $("#gDialog").html(data); + }); + return false; + }); +}); + + diff --git a/modules/organize/views/organize.html.php b/modules/organize/views/organize.html.php new file mode 100644 index 00000000..1686d255 --- /dev/null +++ b/modules/organize/views/organize.html.php @@ -0,0 +1,53 @@ + + + +
            + p::purify($item->title))) ?> +
            +
            +
            +
            +
            +

            +
            +
            +
            +
            +
            +
            +
            + +
            +
            "> +
              +
              +
              +
              +
              +
                +
              +
              +
              +
              +
              + +
              +
              +
              +
              +
              diff --git a/modules/organize/views/organize_album.html.php b/modules/organize/views/organize_album.html.php new file mode 100644 index 00000000..ae2d5d51 --- /dev/null +++ b/modules/organize/views/organize_album.html.php @@ -0,0 +1,17 @@ + +
                +
              • + "> + + +
                gBranchText"> + title) ?> +
                +
                "> + +
                +
              • +
              diff --git a/modules/organize/views/organize_button_pane.html.php b/modules/organize/views/organize_button_pane.html.php index 8eced107..c5839a44 100644 --- a/modules/organize/views/organize_button_pane.html.php +++ b/modules/organize/views/organize_button_pane.html.php @@ -1,5 +1,50 @@ + +
              - + + +
              diff --git a/modules/organize/views/organize_dialog.html.php b/modules/organize/views/organize_dialog.html.php deleted file mode 100644 index cf3fd478..00000000 --- a/modules/organize/views/organize_dialog.html.php +++ /dev/null @@ -1,37 +0,0 @@ - -
              -

              p::purify($item->title))) ?>

              -
              -
              -
              -

              -
              -
              -
              -
              -
              -
              -
              -
                - -
              -
              -
              -
              "> -
                - -
              -
              -
              -
              -
              -
              - -
              -
              -
              -
              -
              -
              - diff --git a/modules/organize/views/organize_edit.html.php b/modules/organize/views/organize_edit.html.php new file mode 100644 index 00000000..1adf290f --- /dev/null +++ b/modules/organize/views/organize_edit.html.php @@ -0,0 +1,14 @@ + +
                + $pane): ?> +
              • + +
              + + 0): ?> + $pane): ?> +
              + + +
              + \ No newline at end of file diff --git a/modules/organize/views/organize_thumb_grid.html.php b/modules/organize/views/organize_thumb_grid.html.php index e6b7aec0..c80696ad 100644 --- a/modules/organize/views/organize_thumb_grid.html.php +++ b/modules/organize/views/organize_thumb_grid.html.php @@ -1,19 +1,12 @@ $child): ?> - - is_album()): ?> - - -
            • + +is_album()): ?> + + +
            • +
              thumb_img(array("class" => "gThumbnail"), $thumbsize, true) ?> -
            • +
              + -= 25): ?> - - \ No newline at end of file diff --git a/modules/organize/views/organize_tree.html.php b/modules/organize/views/organize_tree.html.php index 28b45be0..d2cdd957 100644 --- a/modules/organize/views/organize_tree.html.php +++ b/modules/organize/views/organize_tree.html.php @@ -1,20 +1,4 @@ -
            • - "> - - -
              gBranchText"> - title) ?> -
              - -
              - -
                "> - -
              - -
            • + $child): ?> + -- cgit v1.2.3 From 9f396178cedc96abb282e72ff0e843e255c8225a Mon Sep 17 00:00:00 2001 From: Tim Almdal Date: Wed, 5 Aug 2009 09:24:27 -0700 Subject: Revert "Allow a theme to override the page refresh mechanism. Create a new" This reverts commit 1f014aae6c16bbda62d8f5937180f11ccb0eb1b1. --- lib/gallery.dialog.js | 4 +- lib/gallery.panel.js | 4 +- lib/gallery.reload.js | 16 ----- modules/gallery/js/quick.js | 4 +- modules/gallery/tests/xss_data.txt | 68 +++++++++++----------- .../views/admin_maintenance_show_log.html.php | 2 +- .../gallery/views/admin_maintenance_task.html.php | 2 +- modules/organize/js/organize.js | 2 +- .../views/server_add_tree_dialog.html.php | 2 +- modules/tag/js/tag.js | 2 +- themes/admin_default/views/admin.html.php | 2 - themes/default/views/page.html.php | 2 - 12 files changed, 44 insertions(+), 66 deletions(-) delete mode 100644 lib/gallery.reload.js diff --git a/lib/gallery.dialog.js b/lib/gallery.dialog.js index 0efcf120..74c2f20e 100644 --- a/lib/gallery.dialog.js +++ b/lib/gallery.dialog.js @@ -25,9 +25,9 @@ function ajaxify_dialog() { } if (data.result == "success") { if (data.location) { - $.gallery_location(data.location); + window.location = data.location; } else { - $.gallery_reload(); + window.location.reload(); } } } diff --git a/lib/gallery.panel.js b/lib/gallery.panel.js index 26be11ad..022e4878 100644 --- a/lib/gallery.panel.js +++ b/lib/gallery.panel.js @@ -40,9 +40,9 @@ function togglePanel(element, on_success) { if (on_success) { on_success(); } else if (data.location) { - $.gallery_location(data.location); + window.location = data.location; } else { - $.gallery_reload(); + window.location.reload(); } } } diff --git a/lib/gallery.reload.js b/lib/gallery.reload.js deleted file mode 100644 index 2c8752a0..00000000 --- a/lib/gallery.reload.js +++ /dev/null @@ -1,16 +0,0 @@ -/** - * To change this template, choose Tools | Templates - * and open the template in the editor. - */ -(function ($) { - $.gallery_reload = function() { - window.location.reload(); - }; -})(jQuery); - -// Vertically align a block element's content -(function ($) { - $.gallery_location = function(location) { - window.location = location; - }; -})(jQuery); diff --git a/modules/gallery/js/quick.js b/modules/gallery/js/quick.js index 4753808e..fda6470f 100644 --- a/modules/gallery/js/quick.js +++ b/modules/gallery/js/quick.js @@ -67,9 +67,9 @@ var quick_do = function(cont, pane, img) { img.css("margin-top", 0); } } else if (data.location) { - $.gallery_location(data.location); + window.location = data.location; } else if (data.reload) { - $.gallery_reload(); + window.location.reload(); } } }); diff --git a/modules/gallery/tests/xss_data.txt b/modules/gallery/tests/xss_data.txt index 29d223b7..0e118ce7 100644 --- a/modules/gallery/tests/xss_data.txt +++ b/modules/gallery/tests/xss_data.txt @@ -496,25 +496,24 @@ themes/admin_default/views/admin.html.php 20 DIRTY $theme->s themes/admin_default/views/admin.html.php 21 DIRTY $theme->script("jquery.form.js") themes/admin_default/views/admin.html.php 22 DIRTY $theme->script("jquery-ui.js") themes/admin_default/views/admin.html.php 23 DIRTY $theme->script("gallery.common.js") -themes/admin_default/views/admin.html.php 25 DIRTY $theme->script("gallery.reload.js") -themes/admin_default/views/admin.html.php 30 DIRTY $theme->script("gallery.dialog.js") -themes/admin_default/views/admin.html.php 31 DIRTY $theme->script("superfish/js/superfish.js") -themes/admin_default/views/admin.html.php 32 DIRTY $theme->script("jquery.dropshadow.js") -themes/admin_default/views/admin.html.php 33 DIRTY $theme->script("ui.init.js") -themes/admin_default/views/admin.html.php 35 DIRTY $theme->admin_head() -themes/admin_default/views/admin.html.php 38 DIRTY $theme->body_attributes() -themes/admin_default/views/admin.html.php 39 DIRTY $theme->admin_page_top() -themes/admin_default/views/admin.html.php 45 DIRTY $theme->site_status() -themes/admin_default/views/admin.html.php 47 DIRTY $theme->admin_header_top() -themes/admin_default/views/admin.html.php 50 DIRTY $csrf -themes/admin_default/views/admin.html.php 56 DIRTY $theme->admin_menu() -themes/admin_default/views/admin.html.php 58 DIRTY $theme->admin_header_bottom() -themes/admin_default/views/admin.html.php 64 DIRTY $theme->messages() -themes/admin_default/views/admin.html.php 65 DIRTY $content -themes/admin_default/views/admin.html.php 71 DIRTY $sidebar -themes/admin_default/views/admin.html.php 76 DIRTY $theme->admin_footer() -themes/admin_default/views/admin.html.php 78 DIRTY $theme->admin_credits() -themes/admin_default/views/admin.html.php 82 DIRTY $theme->admin_page_bottom() +themes/admin_default/views/admin.html.php 28 DIRTY $theme->script("gallery.dialog.js") +themes/admin_default/views/admin.html.php 29 DIRTY $theme->script("superfish/js/superfish.js") +themes/admin_default/views/admin.html.php 30 DIRTY $theme->script("jquery.dropshadow.js") +themes/admin_default/views/admin.html.php 31 DIRTY $theme->script("ui.init.js") +themes/admin_default/views/admin.html.php 33 DIRTY $theme->admin_head() +themes/admin_default/views/admin.html.php 36 DIRTY $theme->body_attributes() +themes/admin_default/views/admin.html.php 37 DIRTY $theme->admin_page_top() +themes/admin_default/views/admin.html.php 43 DIRTY $theme->site_status() +themes/admin_default/views/admin.html.php 45 DIRTY $theme->admin_header_top() +themes/admin_default/views/admin.html.php 48 DIRTY $csrf +themes/admin_default/views/admin.html.php 54 DIRTY $theme->admin_menu() +themes/admin_default/views/admin.html.php 56 DIRTY $theme->admin_header_bottom() +themes/admin_default/views/admin.html.php 62 DIRTY $theme->messages() +themes/admin_default/views/admin.html.php 63 DIRTY $content +themes/admin_default/views/admin.html.php 69 DIRTY $sidebar +themes/admin_default/views/admin.html.php 74 DIRTY $theme->admin_footer() +themes/admin_default/views/admin.html.php 76 DIRTY $theme->admin_credits() +themes/admin_default/views/admin.html.php 80 DIRTY $theme->admin_page_bottom() themes/admin_default/views/block.html.php 2 DIRTY $id themes/admin_default/views/block.html.php 2 DIRTY $css_id themes/admin_default/views/block.html.php 5 DIRTY $id @@ -602,22 +601,21 @@ themes/default/views/page.html.php 48 DIRTY $theme->s themes/default/views/page.html.php 49 DIRTY $theme->script("jquery.form.js") themes/default/views/page.html.php 50 DIRTY $theme->script("jquery-ui.js") themes/default/views/page.html.php 51 DIRTY $theme->script("gallery.common.js") -themes/default/views/page.html.php 53 DIRTY $theme->script("gallery.reload.js") -themes/default/views/page.html.php 58 DIRTY $theme->script("gallery.dialog.js") -themes/default/views/page.html.php 59 DIRTY $theme->script("gallery.form.js") -themes/default/views/page.html.php 60 DIRTY $theme->script("superfish/js/superfish.js") -themes/default/views/page.html.php 61 DIRTY $theme->script("jquery.localscroll.js") -themes/default/views/page.html.php 62 DIRTY $theme->script("ui.init.js") -themes/default/views/page.html.php 66 DIRTY $theme->script("jquery.scrollTo.js") -themes/default/views/page.html.php 67 DIRTY $theme->script("gallery.show_full_size.js") -themes/default/views/page.html.php 69 DIRTY $theme->script("flowplayer.js") -themes/default/views/page.html.php 72 DIRTY $theme->head() -themes/default/views/page.html.php 75 DIRTY $theme->body_attributes() -themes/default/views/page.html.php 76 DIRTY $theme->page_top() -themes/default/views/page.html.php 78 DIRTY $theme->site_status() -themes/default/views/page.html.php 86 DIRTY $theme->messages() -themes/default/views/page.html.php 87 DIRTY $content -themes/default/views/page.html.php 101 DIRTY $theme->page_bottom() +themes/default/views/page.html.php 56 DIRTY $theme->script("gallery.dialog.js") +themes/default/views/page.html.php 57 DIRTY $theme->script("gallery.form.js") +themes/default/views/page.html.php 58 DIRTY $theme->script("superfish/js/superfish.js") +themes/default/views/page.html.php 59 DIRTY $theme->script("jquery.localscroll.js") +themes/default/views/page.html.php 60 DIRTY $theme->script("ui.init.js") +themes/default/views/page.html.php 64 DIRTY $theme->script("jquery.scrollTo.js") +themes/default/views/page.html.php 65 DIRTY $theme->script("gallery.show_full_size.js") +themes/default/views/page.html.php 67 DIRTY $theme->script("flowplayer.js") +themes/default/views/page.html.php 70 DIRTY $theme->head() +themes/default/views/page.html.php 73 DIRTY $theme->body_attributes() +themes/default/views/page.html.php 74 DIRTY $theme->page_top() +themes/default/views/page.html.php 76 DIRTY $theme->site_status() +themes/default/views/page.html.php 84 DIRTY $theme->messages() +themes/default/views/page.html.php 85 DIRTY $content +themes/default/views/page.html.php 99 DIRTY $theme->page_bottom() themes/default/views/pager.html.php 13 DIRTY $url themes/default/views/pager.html.php 20 DIRTY $previous_page themes/default/views/pager.html.php 20 DIRTY $url diff --git a/modules/gallery/views/admin_maintenance_show_log.html.php b/modules/gallery/views/admin_maintenance_show_log.html.php index ac593de7..9d850986 100644 --- a/modules/gallery/views/admin_maintenance_show_log.html.php +++ b/modules/gallery/views/admin_maintenance_show_log.html.php @@ -1,7 +1,7 @@
              diff --git a/modules/organize/js/organize.js b/modules/organize/js/organize.js index 12d8a5b5..f10cbcc9 100644 --- a/modules/organize/js/organize.js +++ b/modules/organize/js/organize.js @@ -374,7 +374,7 @@ function organize_dialog_init() { } $("#gDialog").bind("organize_close", function(target) { - $.gallery_reload(); + document.location.reload(); }); heightMicroThumbPanel -= 2 * parseFloat($("#gDialog").css("padding-top")); diff --git a/modules/server_add/views/server_add_tree_dialog.html.php b/modules/server_add/views/server_add_tree_dialog.html.php index 8dfd2c38..21952849 100644 --- a/modules/server_add/views/server_add_tree_dialog.html.php +++ b/modules/server_add/views/server_add_tree_dialog.html.php @@ -34,7 +34,7 @@ - diff --git a/modules/tag/js/tag.js b/modules/tag/js/tag.js index 564de393..765c2a35 100644 --- a/modules/tag/js/tag.js +++ b/modules/tag/js/tag.js @@ -59,7 +59,7 @@ function editInPlace(element) { closeEditInPlaceForms(); // close form $("#gTag-" + data.tag_id).text(data.new_tagname); // update tagname console.log(data); - $.gallery_reload(); + window.location.reload(); } } }); diff --git a/themes/admin_default/views/admin.html.php b/themes/admin_default/views/admin.html.php index 63fc45b5..d27f9260 100644 --- a/themes/admin_default/views/admin.html.php +++ b/themes/admin_default/views/admin.html.php @@ -21,8 +21,6 @@ script("jquery.form.js") ?> script("jquery-ui.js") ?> script("gallery.common.js") ?> - - script("gallery.reload.js") ?>
              diff --git a/modules/organize/js/organize.js b/modules/organize/js/organize.js index f10cbcc9..12d8a5b5 100644 --- a/modules/organize/js/organize.js +++ b/modules/organize/js/organize.js @@ -374,7 +374,7 @@ function organize_dialog_init() { } $("#gDialog").bind("organize_close", function(target) { - document.location.reload(); + $.gallery_reload(); }); heightMicroThumbPanel -= 2 * parseFloat($("#gDialog").css("padding-top")); diff --git a/modules/server_add/views/server_add_tree_dialog.html.php b/modules/server_add/views/server_add_tree_dialog.html.php index 21952849..8dfd2c38 100644 --- a/modules/server_add/views/server_add_tree_dialog.html.php +++ b/modules/server_add/views/server_add_tree_dialog.html.php @@ -34,7 +34,7 @@ - diff --git a/modules/tag/js/tag.js b/modules/tag/js/tag.js index 765c2a35..564de393 100644 --- a/modules/tag/js/tag.js +++ b/modules/tag/js/tag.js @@ -59,7 +59,7 @@ function editInPlace(element) { closeEditInPlaceForms(); // close form $("#gTag-" + data.tag_id).text(data.new_tagname); // update tagname console.log(data); - window.location.reload(); + $.gallery_reload(); } } }); diff --git a/themes/admin_default/views/admin.html.php b/themes/admin_default/views/admin.html.php index d27f9260..63fc45b5 100644 --- a/themes/admin_default/views/admin.html.php +++ b/themes/admin_default/views/admin.html.php @@ -21,6 +21,8 @@ script("jquery.form.js") ?> script("jquery-ui.js") ?> script("gallery.common.js") ?> + + script("gallery.reload.js") ?> -
              - p::purify($item->title))) ?> -
              -
              -
              -
              -
              -

              -
              -
              -
              -
              -
              -
              -
              - -
              -
              "> -
                -
                -
                -
                -
                -
                  -
                -
                -
                -
                -
                - -
                -
                -
                -
                -
                diff --git a/modules/organize/views/organize_album.html.php b/modules/organize/views/organize_album.html.php deleted file mode 100644 index ae2d5d51..00000000 --- a/modules/organize/views/organize_album.html.php +++ /dev/null @@ -1,17 +0,0 @@ - -
                  -
                • - "> - - -
                  gBranchText"> - title) ?> -
                  -
                  "> - -
                  -
                • -
                diff --git a/modules/organize/views/organize_button_pane.html.php b/modules/organize/views/organize_button_pane.html.php index c5839a44..8eced107 100644 --- a/modules/organize/views/organize_button_pane.html.php +++ b/modules/organize/views/organize_button_pane.html.php @@ -1,50 +1,5 @@ - -
                - - - +
                diff --git a/modules/organize/views/organize_dialog.html.php b/modules/organize/views/organize_dialog.html.php new file mode 100644 index 00000000..cf3fd478 --- /dev/null +++ b/modules/organize/views/organize_dialog.html.php @@ -0,0 +1,37 @@ + +
                +

                p::purify($item->title))) ?>

                +
                +
                +
                +

                +
                +
                +
                +
                +
                +
                +
                +
                  + +
                +
                +
                +
                "> +
                  + +
                +
                +
                +
                +
                +
                + +
                +
                +
                +
                +
                +
                + diff --git a/modules/organize/views/organize_edit.html.php b/modules/organize/views/organize_edit.html.php deleted file mode 100644 index 1adf290f..00000000 --- a/modules/organize/views/organize_edit.html.php +++ /dev/null @@ -1,14 +0,0 @@ - -
                  - $pane): ?> -
                • - -
                - - 0): ?> - $pane): ?> -
                - - -
                - \ No newline at end of file diff --git a/modules/organize/views/organize_thumb_grid.html.php b/modules/organize/views/organize_thumb_grid.html.php index c80696ad..e6b7aec0 100644 --- a/modules/organize/views/organize_thumb_grid.html.php +++ b/modules/organize/views/organize_thumb_grid.html.php @@ -1,12 +1,19 @@ $child): ?> - -is_album()): ?> - - -
              • -
                + + is_album()): ?> + + +
              • thumb_img(array("class" => "gThumbnail"), $thumbsize, true) ?> -
              • - + += 25): ?> + + \ No newline at end of file diff --git a/modules/organize/views/organize_tree.html.php b/modules/organize/views/organize_tree.html.php index d2cdd957..28b45be0 100644 --- a/modules/organize/views/organize_tree.html.php +++ b/modules/organize/views/organize_tree.html.php @@ -1,4 +1,20 @@ - $child): ?> - +
              • + "> + + +
                gBranchText"> + title) ?> +
                + +
                + +
                  "> + +
                + +
              • -- cgit v1.2.3 From 63f3efef37839ffba8cd75b9098d56cd03b06376 Mon Sep 17 00:00:00 2001 From: Tim Almdal Date: Wed, 5 Aug 2009 10:26:49 -0700 Subject: Revert "Revert "Enable the expand/collapse of branches by clicking on the plus/minus"" This reverts commit e37526f94df74a52a9cf36f0a5a5e641958ebbb3. --- modules/organize/controllers/organize.php | 59 ++++++++++++++++--------- modules/organize/css/organize.css | 8 ++++ modules/organize/js/organize.js | 28 +++++++++++- modules/organize/views/organize_dialog.html.php | 2 +- modules/organize/views/organize_tree.html.php | 10 +++-- 5 files changed, 80 insertions(+), 27 deletions(-) diff --git a/modules/organize/controllers/organize.php b/modules/organize/controllers/organize.php index d7854c53..e10e33b5 100644 --- a/modules/organize/controllers/organize.php +++ b/modules/organize/controllers/organize.php @@ -50,6 +50,27 @@ class Organize_Controller extends Controller { print $v->__toString(); } + function children($item_id) { + $item = ORM::factory("item", $item_id); + access::required("view", $item); + access::required("edit", $item); + + $albums = $item->children(null, 0, "album", array("title" => "ASC")); + + $children = ""; + foreach ($albums as $album) { + $v = new View("organize_tree.html"); + $v->album = $album; + $v->selected = false; + $v->children = array(); + $v->album_icon = $album->children_count("album") ? "ui-icon-plus" : "gBranchEmpty"; + + $children .= $v->__toString(); + } + + print $children; + } + private function _get_micro_thumb_grid($item, $offset=0) { $v = new View("organize_thumb_grid.html"); $v->item_id = $item->id; @@ -60,34 +81,30 @@ class Organize_Controller extends Controller { return $v; } - private function _tree($item, $parent, $selected=false) { - access::required("view", $item); - access::required("edit", $item); - - $albums = ORM::factory("item") - ->where(array("parent_id" => $parent->id, "type" => "album")) - ->orderby(array("title" => "ASC")) - ->find_all(); + private function _tree($item, $parent, $depth=0) { + $albums = $parent->children(null, 0, "album", array("title" => "ASC")); $v = new View("organize_tree.html"); $v->album = $parent; - $v->selected = false; - $v->children = ""; - $v->album_icon = "ui-icon-plus"; - if (!$selected) { - $v->selected = $parent->id == $item->id; + if ($parent->id == $item->id) { + $v->selected = true; + $depth = 1; + } else { + $v->selected = false; + } + $v->children = array(); + $v->album_icon = "gBranchEmpty"; + if ($albums->count()) { + $v->album_icon = "ui-icon-plus"; - if ($albums->count() && ($parent->id == 1 || $v->selected) ) { + if ($depth <= 1) { $v->album_icon = "ui-icon-minus"; - } - - foreach ($albums as $album) { - $v->children .= $this->_tree($item, $album, $v->selected); + foreach ($albums as $album) { + $v->children[] = $this->_tree($item, $album, ++$depth); + } } } - return $v->__toString(); + return $v; } - - } diff --git a/modules/organize/css/organize.css b/modules/organize/css/organize.css index 4568a707..7c2d9c5b 100644 --- a/modules/organize/css/organize.css +++ b/modules/organize/css/organize.css @@ -41,6 +41,14 @@ padding-left: 1.2em; } +.gBranchText:hover { + border: 1px dashed #999; +} + +.gBranchEmpty { + visibility: hidden; +} + .gBranchSelected { background-color: #cfdeff !important; border-bottom: 1px solid #999 !important; diff --git a/modules/organize/js/organize.js b/modules/organize/js/organize.js index e84afd03..74b02569 100644 --- a/modules/organize/js/organize.js +++ b/modules/organize/js/organize.js @@ -37,7 +37,6 @@ * Dynamically initialize the organize dialog when it is displayed */ function _init(data) { - // Deal with ui.jquery bug: http://dev.jqueryui.com/ticket/4475 $(".sf-menu li.sfHover ul").css("z-index", 70); @@ -64,6 +63,8 @@ $.gallery_reload(); }); + $(".gBranchText span").click(_collapse_or_expanded_tree); + //$(".gOrganizeBranch .ui-icon").click(organizeToggleChildren); //$(".gBranchText").droppable(treeDroppable); //$(".gBranchText").click(organizeOpenFolder); @@ -109,6 +110,31 @@ $("#gOrganizeDialog").dialog("close"); }; + /** + * Open or close a branch. If the children is a div placeholder, replace with
                  + */ + function _collapse_or_expanded_tree(event) { + var id = $(event.currentTarget).attr("ref"); + if ($(event.currentTarget).hasClass("ui-icon-minus")) { + $(event.currentTarget).removeClass("ui-icon-minus"); + $(event.currentTarget).addClass("ui-icon-plus"); + $("#gOrganizeChildren-" + id).hide(); + } else { + if ($("#gOrganizeChildren-" + id).is("div")) { + $("#gOrganizeChildren-" + id).remove(); + $("#gOrganizeBranch-" + id).after("
                    "); + var url = $("#gOrganizeAlbumTree").attr("ref").replace("__ITEM_ID__", id); + $.get(url, function(data) { + $("#gOrganizeChildren-" + id).html(data); + $(".gBranchText span").click(_collapse_or_expanded_tree); + });; + } + $("#gOrganizeChildren-" + id).show(); + $(event.currentTarget).removeClass("ui-icon-plus"); + $(event.currentTarget).addClass("ui-icon-minus"); + } + } + })(jQuery); $("document").ready(function() { diff --git a/modules/organize/views/organize_dialog.html.php b/modules/organize/views/organize_dialog.html.php index cf3fd478..1e6646e4 100644 --- a/modules/organize/views/organize_dialog.html.php +++ b/modules/organize/views/organize_dialog.html.php @@ -12,7 +12,7 @@
                  -
                    +
                      ">
                  diff --git a/modules/organize/views/organize_tree.html.php b/modules/organize/views/organize_tree.html.php index 28b45be0..d64410d8 100644 --- a/modules/organize/views/organize_tree.html.php +++ b/modules/organize/views/organize_tree.html.php @@ -1,11 +1,11 @@
                • - "> -
                  gBranchText"> + + title) ?>
                  @@ -13,7 +13,9 @@
                    "> - + + +
                • -- cgit v1.2.3 From e8c57290a2e98e3cbb7cf47875e6e5dae2e41fa2 Mon Sep 17 00:00:00 2001 From: Bharat Mediratta Date: Wed, 5 Aug 2009 10:38:53 -0700 Subject: Change the children and descendants APIs to be more consistent and to remove Gallery3 concepts from ORM_MPTT. The following API methods: ORM_MPTT::children ORM_MPTT::children_count ORM_MPTT::descendants ORM_MPTT::descendants_count All now take a $where clause that allow you to pass through additional field parameters. old API: $album->children(10, 0, "photos") $album->children_count("photos") new API: $album->children(10, 0, array("type" => "photos")) $album->children_count(array("type" => "photos")) This gives us a more flexible API and simplifies the code. While I was in there, I changed the way we deal with default orderby values so that we just assign the default value in the function definition, which allows us to get rid of all conditionals in the implementation which results in simpler code. --- modules/gallery/helpers/gallery_rss.php | 5 ++- modules/gallery/libraries/ORM_MPTT.php | 69 +++++++++++++-------------------- modules/gallery/models/item.php | 25 +++++++----- modules/gallery/tests/ORM_MPTT_Test.php | 8 ++-- 4 files changed, 51 insertions(+), 56 deletions(-) diff --git a/modules/gallery/helpers/gallery_rss.php b/modules/gallery/helpers/gallery_rss.php index 7daf6170..8e887368 100644 --- a/modules/gallery/helpers/gallery_rss.php +++ b/modules/gallery/helpers/gallery_rss.php @@ -50,8 +50,9 @@ class gallery_rss_Core { $feed->children = $item ->viewable() - ->descendants($limit, $offset, "photo"); - $feed->max_pages = ceil($item->viewable()->descendants_count("photo") / $limit); + ->descendants($limit, $offset, array("type" => "photo")); + $feed->max_pages = ceil( + $item->viewable()->descendants_count(array("type" => "photo")) / $limit); $feed->title = p::purify($item->title); $feed->link = url::abs_site("albums/{$item->id}"); $feed->description = nl2br(p::purify($item->description)); diff --git a/modules/gallery/libraries/ORM_MPTT.php b/modules/gallery/libraries/ORM_MPTT.php index cde049cd..9d716d8b 100644 --- a/modules/gallery/libraries/ORM_MPTT.php +++ b/modules/gallery/libraries/ORM_MPTT.php @@ -146,35 +146,30 @@ class ORM_MPTT_Core extends ORM { * @chainable * @param integer SQL limit * @param integer SQL offset - * @param string type to return + * @param array additional where clauses * @param array orderby * @return array ORM */ - function children($limit=null, $offset=0, $type=null, $orderby=null) { - $this->where("parent_id", $this->id); - if ($type) { - $this->where("type", $type); - } - if (empty($orderby)) { - $this->orderby("id", "ASC"); - } else { - $this->orderby($orderby); - } - return $this->find_all($limit, $offset); + function children($limit=null, $offset=0, $where=array(), $orderby=array("id", "ASC")) { + return $this + ->where("parent_id", $this->id) + ->where($where) + ->orderby($orderby) + ->find_all($limit, $offset); } /** * Return all of the children of this node, ordered by id. * * @chainable - * @param string type to return + * @param array additional where clauses * @return array ORM */ - function children_count($type=null) { - if ($type) { - $this->where("type", $type); - } - return $this->where("parent_id", $this->id)->count_all(); + function children_count($where=array()) { + return $this + ->where($where) + ->where("parent_id", $this->id) + ->count_all(); } /** @@ -182,39 +177,31 @@ class ORM_MPTT_Core extends ORM { * * @param integer SQL limit * @param integer SQL offset - * @param string type to return + * @param array additional where clauses * @param array orderby * @return object ORM_Iterator */ - function descendants($limit=null, $offset=0, $type=null, $orderby=null) { - $this->where("left_ptr >", $this->left_ptr) - ->where("right_ptr <=", $this->right_ptr); - if ($type) { - $this->where("type", $type); - } - - if (empty($orderby)) { - $this->orderby("id", "ASC"); - } else { - $this->orderby($orderby); - } - - return $this->find_all($limit, $offset); + function descendants($limit=null, $offset=0, $where=array(), $orderby=array("id", "ASC")) { + return $this + ->where("left_ptr >", $this->left_ptr) + ->where("right_ptr <=", $this->right_ptr) + ->where($where) + ->orderby($orderby) + ->find_all($limit, $offset); } /** * Return the count of all the children of the specified type. * - * @param string type to count + * @param array additional where clauses * @return integer child count */ - function descendants_count($type=null) { - $this->where("left_ptr >", $this->left_ptr) - ->where("right_ptr <=", $this->right_ptr); - if ($type) { - $this->where("type", $type); - } - return $this->count_all(); + function descendants_count($where=array()) { + return $this + ->where("left_ptr >", $this->left_ptr) + ->where("right_ptr <=", $this->right_ptr) + ->where($where) + ->count_all(); } /** diff --git a/modules/gallery/models/item.php b/modules/gallery/models/item.php index 3498e0db..c4b9826f 100644 --- a/modules/gallery/models/item.php +++ b/modules/gallery/models/item.php @@ -521,31 +521,38 @@ class Item_Model extends ORM_MPTT { } /** - * Return all of the children of this node, ordered by the defined sort order. + * Return all of the children of this album. Unless you specify a specific sort order, the + * results will be ordered by this album's sort order. * * @chainable * @param integer SQL limit * @param integer SQL offset - * @param string type to return + * @param array additional where clauses * @param array orderby * @return array ORM */ - function children($limit=null, $offset=0, $type=null, $orderby=null) { + function children($limit=null, $offset=0, $where=array(), $orderby=null) { if (empty($orderby)) { $orderby = array($this->sort_column => $this->sort_order); } - return parent::children($limit, $offset, $type, $orderby); + return parent::children($limit, $offset, $where, $orderby); } /** - * Return all of the children of the specified type, ordered by the defined sort order. + * Return the children of this album, and all of it's sub-albums. Unless you specify a specific + * sort order, the results will be ordered by this album's sort order. Note that this + * album's sort order is imposed on all sub-albums, regardless of their sort order. + * + * @chainable * @param integer SQL limit * @param integer SQL offset - * @param string type to return + * @param array additional where clauses * @return object ORM_Iterator */ - function descendants($limit=null, $offset=0, $type=null) { - return parent::descendants($limit, $offset, $type, - array($this->sort_column => $this->sort_order)); + function descendants($limit=null, $offset=0, $where=array(), $orderby=null) { + if (empty($orderby)) { + $orderby = array($this->sort_column => $this->sort_order); + } + return parent::descendants($limit, $offset, $where, $orderby); } } diff --git a/modules/gallery/tests/ORM_MPTT_Test.php b/modules/gallery/tests/ORM_MPTT_Test.php index 943810c3..f77f1f34 100644 --- a/modules/gallery/tests/ORM_MPTT_Test.php +++ b/modules/gallery/tests/ORM_MPTT_Test.php @@ -177,8 +177,8 @@ class ORM_MPTT_Test extends Unit_Test_Case { $parent->reload(); $this->assert_equal(3, $parent->descendants()->count()); - $this->assert_equal(2, $parent->descendants(null, 0, "photo")->count()); - $this->assert_equal(1, $parent->descendants(null, 0, "album")->count()); + $this->assert_equal(2, $parent->descendants(null, 0, array("type" => "photo"))->count()); + $this->assert_equal(1, $parent->descendants(null, 0, array("type" => "album"))->count()); } public function descendant_limit_test() { @@ -215,7 +215,7 @@ class ORM_MPTT_Test extends Unit_Test_Case { $parent->reload(); $this->assert_equal(3, $parent->descendants_count()); - $this->assert_equal(2, $parent->descendants_count("photo")); - $this->assert_equal(1, $parent->descendants_count("album")); + $this->assert_equal(2, $parent->descendants_count(array("type" => "photo"))); + $this->assert_equal(1, $parent->descendants_count(array("type" => "album"))); } } -- cgit v1.2.3 From b394b0b2c67d680fad61880a01885e8b2c750ce5 Mon Sep 17 00:00:00 2001 From: Bharat Mediratta Date: Wed, 5 Aug 2009 11:01:48 -0700 Subject: Fix the default $orderby to be an associative array in descendants() and children(), thanks Tim! --- modules/gallery/libraries/ORM_MPTT.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/gallery/libraries/ORM_MPTT.php b/modules/gallery/libraries/ORM_MPTT.php index 9d716d8b..a7defba9 100644 --- a/modules/gallery/libraries/ORM_MPTT.php +++ b/modules/gallery/libraries/ORM_MPTT.php @@ -150,7 +150,7 @@ class ORM_MPTT_Core extends ORM { * @param array orderby * @return array ORM */ - function children($limit=null, $offset=0, $where=array(), $orderby=array("id", "ASC")) { + function children($limit=null, $offset=0, $where=array(), $orderby=array("id" => "ASC")) { return $this ->where("parent_id", $this->id) ->where($where) @@ -181,7 +181,7 @@ class ORM_MPTT_Core extends ORM { * @param array orderby * @return object ORM_Iterator */ - function descendants($limit=null, $offset=0, $where=array(), $orderby=array("id", "ASC")) { + function descendants($limit=null, $offset=0, $where=array(), $orderby=array("id" => "ASC")) { return $this ->where("left_ptr >", $this->left_ptr) ->where("right_ptr <=", $this->right_ptr) -- cgit v1.2.3 From a92a46b0cda18a3ba794a67c07181a2ca405a2a6 Mon Sep 17 00:00:00 2001 From: Tim Almdal Date: Wed, 5 Aug 2009 11:04:42 -0700 Subject: Change to use the new children and children_count API --- modules/organize/controllers/organize.php | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/modules/organize/controllers/organize.php b/modules/organize/controllers/organize.php index e10e33b5..cbaaca6e 100644 --- a/modules/organize/controllers/organize.php +++ b/modules/organize/controllers/organize.php @@ -55,7 +55,7 @@ class Organize_Controller extends Controller { access::required("view", $item); access::required("edit", $item); - $albums = $item->children(null, 0, "album", array("title" => "ASC")); + $albums = $item->children(null, 0, array("type" => "album"), array("title" => "ASC")); $children = ""; foreach ($albums as $album) { @@ -63,7 +63,8 @@ class Organize_Controller extends Controller { $v->album = $album; $v->selected = false; $v->children = array(); - $v->album_icon = $album->children_count("album") ? "ui-icon-plus" : "gBranchEmpty"; + $v->album_icon = + $album->children_count(array("type" => "album")) ? "ui-icon-plus" : "gBranchEmpty"; $children .= $v->__toString(); } @@ -82,7 +83,7 @@ class Organize_Controller extends Controller { } private function _tree($item, $parent, $depth=0) { - $albums = $parent->children(null, 0, "album", array("title" => "ASC")); + $albums = $parent->children(null, 0, array("type" => "album"), array("title" => "ASC")); $v = new View("organize_tree.html"); $v->album = $parent; -- cgit v1.2.3 From 824a80b0d4b5c12f5bd6981cac08b406de637dd3 Mon Sep 17 00:00:00 2001 From: Tim Almdal Date: Wed, 5 Aug 2009 15:24:31 -0700 Subject: Change the content pane based on the selection in the album tree --- modules/organize/js/organize.js | 26 ++++++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/modules/organize/js/organize.js b/modules/organize/js/organize.js index 74b02569..194a2a19 100644 --- a/modules/organize/js/organize.js +++ b/modules/organize/js/organize.js @@ -64,12 +64,10 @@ }); $(".gBranchText span").click(_collapse_or_expanded_tree); + $(".gBranchText").click(_setContents); //$(".gOrganizeBranch .ui-icon").click(organizeToggleChildren); //$(".gBranchText").droppable(treeDroppable); - //$(".gBranchText").click(organizeOpenFolder); - //retrieveMicroThumbs(item_id); - //showLoading("#gOrganizeDialog"); //$("#gMicroThumbPanel").droppable(thumbDroppable); //$("#gMicroThumbPanel").selectable(selectable); @@ -114,6 +112,7 @@ * Open or close a branch. If the children is a div placeholder, replace with
                    */ function _collapse_or_expanded_tree(event) { + event.stopPropagation(); var id = $(event.currentTarget).attr("ref"); if ($(event.currentTarget).hasClass("ui-icon-minus")) { $(event.currentTarget).removeClass("ui-icon-minus"); @@ -127,7 +126,8 @@ $.get(url, function(data) { $("#gOrganizeChildren-" + id).html(data); $(".gBranchText span").click(_collapse_or_expanded_tree); - });; + $(".gBranchText").click(_setContents); + }); } $("#gOrganizeChildren-" + id).show(); $(event.currentTarget).removeClass("ui-icon-plus"); @@ -135,6 +135,24 @@ } } + /** + * When the text of a selection is clicked, then show that albums contents + */ + function _setContents(event) { + event.preventDefault(); + if ($(event.currentTarget).hasClass("gBranchSelected")) { + return; + } + var id = $(event.currentTarget).attr("ref"); + $(".gBranchSelected").removeClass("gBranchSelected"); + $(event.currentTarget).addClass("gBranchSelected"); + var url = $("#gMicroThumbPanel").attr("ref").replace("__ITEM_ID__", id).replace("__OFFSET__", 0); + $.get(url, function(data) { + $("#gMicroThumbGrid").html(data); + }); + + } + })(jQuery); $("document").ready(function() { -- cgit v1.2.3 From a03f8b1003093b385e9c839c1e5e2e4f80f0cd0b Mon Sep 17 00:00:00 2001 From: Tim Almdal Date: Wed, 5 Aug 2009 16:45:44 -0700 Subject: Fix up formatting of items in thumbgrid --- modules/organize/css/organize.css | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/modules/organize/css/organize.css b/modules/organize/css/organize.css index 7c2d9c5b..0a23a6bf 100644 --- a/modules/organize/css/organize.css +++ b/modules/organize/css/organize.css @@ -83,6 +83,7 @@ } #gMicroThumbGrid { + padding: .5em; } .gMicroThumbContainer { @@ -93,7 +94,7 @@ .gMicroThumb { display: block; float: left; -// font-size: .7em; + font-size: .8em; height: 9em; margin-bottom: 1em; margin-left: 1em; @@ -101,6 +102,10 @@ width: 9em; } +.gThumbnail { + padding: .5em; +} + #gMicroThumbPanel #gMicroThumbGrid .gAlbum { background-color: #e8e8e8; } -- cgit v1.2.3 From f0b3d37d18c19a170dc737dc01e002d26535a9b3 Mon Sep 17 00:00:00 2001 From: Bharat Mediratta Date: Wed, 5 Aug 2009 22:17:03 -0700 Subject: Chain some jQuery calls together to reduce lines of code. --- modules/server_add/js/server_add.js | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/modules/server_add/js/server_add.js b/modules/server_add/js/server_add.js index 989555cc..3348de4b 100644 --- a/modules/server_add/js/server_add.js +++ b/modules/server_add/js/server_add.js @@ -4,11 +4,9 @@ function select_file(li) { $(li).toggleClass("selected"); if ($("#gServerAdd span.selected").length) { - $("#gServerAddAddButton").enable(true); - $("#gServerAddAddButton").removeClass("ui-state-disabled"); + $("#gServerAddAddButton").enable(true).removeClass("ui-state-disabled"); } else { - $("#gServerAddAddButton").enable(false); - $("#gServerAddAddButton").addClass("ui-state-disabled"); + $("#gServerAddAddButton").enable(false).addClass("ui-state-disabled"); } } -- cgit v1.2.3 From cab46cf0386061840498f3efe32c7030e07d2e04 Mon Sep 17 00:00:00 2001 From: Tim Almdal Date: Wed, 5 Aug 2009 22:28:37 -0700 Subject: Remove the resize dialog on window resize functionality --- modules/organize/js/organize.js | 41 +++++++++++++---------------------------- 1 file changed, 13 insertions(+), 28 deletions(-) diff --git a/modules/organize/js/organize.js b/modules/organize/js/organize.js index 194a2a19..12712ff1 100644 --- a/modules/organize/js/organize.js +++ b/modules/organize/js/organize.js @@ -65,6 +65,7 @@ $(".gBranchText span").click(_collapse_or_expanded_tree); $(".gBranchText").click(_setContents); + $(".gAlbum img.gThumbnail").live("dblclick", _openAlbum); //$(".gOrganizeBranch .ui-icon").click(organizeToggleChildren); //$(".gBranchText").droppable(treeDroppable); @@ -73,34 +74,6 @@ //$("#gMicroThumbPanel").selectable(selectable); //$("#gOrganizeEditDrawerHandle a").click(drawerHandleButtonsClick); - $(window).bind("resize", _size_dialog); - }; - - /** - * Dynamically initialize the organize dialog when it is displayed - */ - function _size_dialog(event) { - var size = $.getViewportSize(); - var h = $("#gOrganizeDialog").dialog("option", "minHeight"); - var sh = size.height() - 100; - var height = Math.max(sh, h); - var w = $("#gOrganizeDialog").dialog("option", "minWidth"); - var sw = size.width() - 100; - var width = Math.max(w, sw); - - $("#gOrganizeDialog").parent().css("height", height); - $("#gOrganizeDialog").parent().css("width", width); - $("#gOrganizeDialog").parent().css("left", "50px"); - $("#gOrganizeDialog").parent().css("top", "50px"); - - var heightMicroThumbPanel = height - 50; - heightMicroThumbPanel -= 2 * parseFloat($("#gOrganizeDialog").css("padding-bottom")); - heightMicroThumbPanel -= $("#gMessage").outerHeight(); - heightMicroThumbPanel = Math.floor(heightMicroThumbPanel); - $("#gOrganizeTreeContainer").height(heightMicroThumbPanel); - - heightMicroThumbPanel -= $("#gOrganizeEditDrawerHandle").outerHeight(); - $("#gMicroThumbPanel").height(heightMicroThumbPanel); }; function _dialog_close(event) { @@ -150,7 +123,19 @@ $.get(url, function(data) { $("#gMicroThumbGrid").html(data); }); + } + function _openAlbum(event) { + event.preventDefault(); + var id = $(event.target).parent().attr("ref"); + $(".gBranchSelected").removeClass("gBranchSelected"); + $("#gOrganizeBranch-" + id).addClass("gBranchSelected"); + var url = $("#gMicroThumbPanel").attr("ref").replace("__ITEM_ID__", id).replace("__OFFSET__", 0); + // @todo load the branch elements if required. + $.get(url, function(data) { + $("#gMicroThumbGrid").html(data); + // $(".gAlbum img.gThumbnail").dblclick(_openAlbum); + }); } })(jQuery); -- cgit v1.2.3 From cd5c99668bf578561d978c2549330a338b775199 Mon Sep 17 00:00:00 2001 From: Bharat Mediratta Date: Wed, 5 Aug 2009 22:32:41 -0700 Subject: Don't show the ajaxy login link in the top right corner if we're on the login page itself. --- modules/user/helpers/user_theme.php | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/modules/user/helpers/user_theme.php b/modules/user/helpers/user_theme.php index c5351f8e..4218ff22 100644 --- a/modules/user/helpers/user_theme.php +++ b/modules/user/helpers/user_theme.php @@ -19,9 +19,11 @@ */ class user_theme_Core { static function header_top($theme) { - $view = new View("login.html"); - $view->user = user::active(); - return $view->render(); + if ($theme->page_type != "login") { + $view = new View("login.html"); + $view->user = user::active(); + return $view->render(); + } } static function admin_head($theme) { -- cgit v1.2.3 From 8131e6fa380d52faa7c1dc9a59c2e83a4adb9134 Mon Sep 17 00:00:00 2001 From: Tim Almdal Date: Thu, 6 Aug 2009 06:33:17 -0700 Subject: Tighten up the code by loading all the albums in the tree at once, removing the events to populate the button bar. --- modules/organize/controllers/organize.php | 67 +++++---------- modules/organize/helpers/organize.php | 94 ---------------------- modules/organize/js/organize.js | 47 +---------- .../organize/views/organize_button_pane.html.php | 5 -- modules/organize/views/organize_dialog.html.php | 9 ++- modules/organize/views/organize_tree.html.php | 17 ++-- 6 files changed, 35 insertions(+), 204 deletions(-) delete mode 100644 modules/organize/helpers/organize.php delete mode 100644 modules/organize/views/organize_button_pane.html.php diff --git a/modules/organize/controllers/organize.php b/modules/organize/controllers/organize.php index cbaaca6e..95d71e9c 100644 --- a/modules/organize/controllers/organize.php +++ b/modules/organize/controllers/organize.php @@ -23,21 +23,20 @@ class Organize_Controller extends Controller { function index($item_id) { $item = ORM::factory("item", $item_id); - $root = ($item->id == 1) ? $item : ORM::factory("item", 1); + $root = $item->id == 1 ? $item : ORM::factory("item", 1); access::required("view", $item); access::required("edit", $item); $v = new View("organize_dialog.html"); - $v->root = $root; - $v->item = $item; - $v->album_tree = $this->_tree($item, $root); - $v->micro_thumb_grid = $this->_get_micro_thumb_grid($item); - $v->button_pane = new View("organize_button_pane.html"); - $buttons = (object)array("left" => array(), "middle" =>array(), "right" => array(), - "item" => $item); - module::event("organize_format_button_pane", $buttons); + $v->title = $item->title; + $parents = array(); + foreach ($item->parents() as $parent) { + $parents[$parent->id] = 1; + } + $parents[$item->id] = 1; - $v->button_pane->buttons = $buttons; + $v->album_tree = $this->_tree($root, $parents); + $v->micro_thumb_grid = $this->_get_micro_thumb_grid($item); print $v; } @@ -50,28 +49,6 @@ class Organize_Controller extends Controller { print $v->__toString(); } - function children($item_id) { - $item = ORM::factory("item", $item_id); - access::required("view", $item); - access::required("edit", $item); - - $albums = $item->children(null, 0, array("type" => "album"), array("title" => "ASC")); - - $children = ""; - foreach ($albums as $album) { - $v = new View("organize_tree.html"); - $v->album = $album; - $v->selected = false; - $v->children = array(); - $v->album_icon = - $album->children_count(array("type" => "album")) ? "ui-icon-plus" : "gBranchEmpty"; - - $children .= $v->__toString(); - } - - print $children; - } - private function _get_micro_thumb_grid($item, $offset=0) { $v = new View("organize_thumb_grid.html"); $v->item_id = $item->id; @@ -82,28 +59,20 @@ class Organize_Controller extends Controller { return $v; } - private function _tree($item, $parent, $depth=0) { - $albums = $parent->children(null, 0, array("type" => "album"), array("title" => "ASC")); - + private function _tree($item, $parents) { $v = new View("organize_tree.html"); - $v->album = $parent; - - if ($parent->id == $item->id) { - $v->selected = true; - $depth = 1; - } else { - $v->selected = false; - } + $v->album = $item; + $keys = array_keys($parents); + $v->selected = end($keys) == $item->id; $v->children = array(); $v->album_icon = "gBranchEmpty"; + + $albums = $item->children(null, 0, array("type" => "album"), array("title" => "ASC")); if ($albums->count()) { - $v->album_icon = "ui-icon-plus"; + $v->album_icon = empty($parents[$item->id]) ? "ui-icon-plus" : "ui-icon-minus"; - if ($depth <= 1) { - $v->album_icon = "ui-icon-minus"; - foreach ($albums as $album) { - $v->children[] = $this->_tree($item, $album, ++$depth); - } + foreach ($albums as $album) { + $v->children[] = $this->_tree($album, $parents); } } return $v; diff --git a/modules/organize/helpers/organize.php b/modules/organize/helpers/organize.php deleted file mode 100644 index 25284771..00000000 --- a/modules/organize/helpers/organize.php +++ /dev/null @@ -1,94 +0,0 @@ - "gEditGeneral", "ref" => "general")); - // In this case we know there is only 1 item, but in general we should loop - // and create multiple hidden items. - $generalPane->hidden("item[]")->value($item->id); - $generalPane->input("title")->label(t("Title"))->value($item->title); - $generalPane->textarea("description")->label(t("Description"))->value($item->description); - $generalPane->input("dirname")->label(t("Path Name"))->value($item->name) - ->callback("item::validate_no_slashes") - ->error_messages("no_slashes", t("The directory name can't contain a \"/\"")) - ->callback("item::validate_no_trailing_period") - ->error_messages("no_trailing_period", t("The directory name can't end in \".\"")) - ->callback("item::validate_no_name_conflict") - ->error_messages("conflict", t("The path name is not unique")); - - return $generalPane; - } - - static function get_sort_edit_form($item) { - $sortPane = new Forge("organize/__FUNCTION__", "", "post", - array("id" => "gEditSort", "ref" => "sort")); - $sortPane->hidden("item[]")->value($item->id); - $sortPane->dropdown("column", array("id" => "gAlbumSortColumn")) - ->label(t("Sort by")) - ->options(array("weight" => t("Order Added"), - "captured" => t("Capture Date"), - "created" => t("Creation Date"), - "title" => t("Title"), - "updated" => t("Updated Date"), - "view_count" => t("Number of views"), - "rand_key" => t("Random"))) - ->selected($item->sort_column); - $sortPane->dropdown("direction", array("id" => "gAlbumSortDirection")) - ->label(t("Order")) - ->options(array("ASC" => t("Ascending"), - "DESC" => t("Descending"))) - ->selected($item->sort_order); - - return $sortPane; - } - - static function get_tag_form($itemids) { - $tagPane = new Forge("organize/__FUNCTION__", "", "post", - array("id" => "gEditTags", "ref" => "edit_tags")); - $tagPane->hidden("item")->value(implode("|", $itemids)); - $item_count = count($itemids); - $ids = implode(", ", $itemids); - - // Lame stopgap security check. This code is going to get rewritten anyway. - foreach ($itemids as $id) { - $item = ORM::factory("item", $id); - access::required("view", $item); - access::required("edit", $item); - } - - $tags = Database::instance()->query( - "SELECT t.name, COUNT(it.item_id) as count - FROM {items_tags} it, {tags} t - WHERE it.tag_id = t.id - AND it.item_id in($ids) - GROUP BY it.tag_id - ORDER BY t.name ASC"); - $taglist = array(); - foreach ($tags as $tag) { - $taglist[] = $tag->name . ($item_count > $tag->count ? "*" : ""); - } - $taglist = implode("; ", $taglist); - $tagPane->textarea("tags")->label(t("Tags"))->value($taglist); - - return $tagPane; - } - -} \ No newline at end of file diff --git a/modules/organize/js/organize.js b/modules/organize/js/organize.js index 12712ff1..0a7576b0 100644 --- a/modules/organize/js/organize.js +++ b/modules/organize/js/organize.js @@ -12,7 +12,6 @@ $("body").append('
                    '); $("#gOrganizeDialog").dialog(opts); - // Pass the approx height and width of the thumb grid to optimize thumb retrieval $.get(href, _init); return false; }); @@ -45,8 +44,7 @@ var heightMicroThumbPanel = $("#gOrganizeDialog").innerHeight(); heightMicroThumbPanel -= 2 * parseFloat($("#gOrganizeDialog").css("padding-bottom")); - heightMicroThumbPanel -= $("#gMessage").outerHeight(); - heightMicroThumbPanel = Math.floor(heightMicroThumbPanel); + heightMicroThumbPanel = Math.floor(heightMicroThumbPanel - 10 - $("#gMessage").outerHeight()); $("#gOrganizeTreeContainer").height(heightMicroThumbPanel); heightMicroThumbPanel -= $("#gOrganizeEditDrawerHandle").outerHeight(); @@ -65,15 +63,6 @@ $(".gBranchText span").click(_collapse_or_expanded_tree); $(".gBranchText").click(_setContents); - $(".gAlbum img.gThumbnail").live("dblclick", _openAlbum); - - //$(".gOrganizeBranch .ui-icon").click(organizeToggleChildren); - //$(".gBranchText").droppable(treeDroppable); - - //$("#gMicroThumbPanel").droppable(thumbDroppable); - //$("#gMicroThumbPanel").selectable(selectable); - //$("#gOrganizeEditDrawerHandle a").click(drawerHandleButtonsClick); - }; function _dialog_close(event) { @@ -86,26 +75,12 @@ */ function _collapse_or_expanded_tree(event) { event.stopPropagation(); - var id = $(event.currentTarget).attr("ref"); if ($(event.currentTarget).hasClass("ui-icon-minus")) { - $(event.currentTarget).removeClass("ui-icon-minus"); - $(event.currentTarget).addClass("ui-icon-plus"); - $("#gOrganizeChildren-" + id).hide(); + $(event.currentTarget).removeClass("ui-icon-minus").addClass("ui-icon-plus"); } else { - if ($("#gOrganizeChildren-" + id).is("div")) { - $("#gOrganizeChildren-" + id).remove(); - $("#gOrganizeBranch-" + id).after("
                      "); - var url = $("#gOrganizeAlbumTree").attr("ref").replace("__ITEM_ID__", id); - $.get(url, function(data) { - $("#gOrganizeChildren-" + id).html(data); - $(".gBranchText span").click(_collapse_or_expanded_tree); - $(".gBranchText").click(_setContents); - }); - } - $("#gOrganizeChildren-" + id).show(); - $(event.currentTarget).removeClass("ui-icon-plus"); - $(event.currentTarget).addClass("ui-icon-minus"); + $(event.currentTarget).removeClass("ui-icon-plus").addClass("ui-icon-minus"); } + $("#gOrganizeChildren-" + $(event.currentTarget).attr("ref")).toggle(); } /** @@ -118,26 +93,12 @@ } var id = $(event.currentTarget).attr("ref"); $(".gBranchSelected").removeClass("gBranchSelected"); - $(event.currentTarget).addClass("gBranchSelected"); - var url = $("#gMicroThumbPanel").attr("ref").replace("__ITEM_ID__", id).replace("__OFFSET__", 0); - $.get(url, function(data) { - $("#gMicroThumbGrid").html(data); - }); - } - - function _openAlbum(event) { - event.preventDefault(); - var id = $(event.target).parent().attr("ref"); - $(".gBranchSelected").removeClass("gBranchSelected"); $("#gOrganizeBranch-" + id).addClass("gBranchSelected"); var url = $("#gMicroThumbPanel").attr("ref").replace("__ITEM_ID__", id).replace("__OFFSET__", 0); - // @todo load the branch elements if required. $.get(url, function(data) { $("#gMicroThumbGrid").html(data); - // $(".gAlbum img.gThumbnail").dblclick(_openAlbum); }); } - })(jQuery); $("document").ready(function() { diff --git a/modules/organize/views/organize_button_pane.html.php b/modules/organize/views/organize_button_pane.html.php deleted file mode 100644 index 8eced107..00000000 --- a/modules/organize/views/organize_button_pane.html.php +++ /dev/null @@ -1,5 +0,0 @@ - -
                      - -
                      diff --git a/modules/organize/views/organize_dialog.html.php b/modules/organize/views/organize_dialog.html.php index 1e6646e4..4f10297e 100644 --- a/modules/organize/views/organize_dialog.html.php +++ b/modules/organize/views/organize_dialog.html.php @@ -1,6 +1,6 @@
                      -

                      p::purify($item->title))) ?>

                      +

                      p::purify($title))) ?>

                      @@ -12,7 +12,7 @@
                      -
                        "> +
                      @@ -27,7 +27,10 @@
                      - +
                      + +
                      diff --git a/modules/organize/views/organize_tree.html.php b/modules/organize/views/organize_tree.html.php index d64410d8..280bdc5f 100644 --- a/modules/organize/views/organize_tree.html.php +++ b/modules/organize/views/organize_tree.html.php @@ -8,15 +8,12 @@ title) ?>
                      - -
                      - -
                        "> - - - -
                      - +
                        "> +
                      •  
                      • + + + +
                      -- cgit v1.2.3 From 7bdf382e813515ce7ab6e14f0b8e3e0b7b6bd867 Mon Sep 17 00:00:00 2001 From: Tim Almdal Date: Thu, 6 Aug 2009 07:02:41 -0700 Subject: Revert "Revert "Revert "Allow a theme to override the page refresh mechanism. Create a new""" This reverts commit 7b1cca168cb9b29fcccdcdce9e32efb190e4575e. Basically remove it and Bharat and I will fight it out in SF for a resolution :-) --- lib/gallery.dialog.js | 4 +- lib/gallery.panel.js | 4 +- lib/gallery.reload.js | 16 ----- modules/gallery/js/quick.js | 4 +- modules/gallery/tests/xss_data.txt | 68 +++++++++++----------- .../views/admin_maintenance_show_log.html.php | 2 +- .../gallery/views/admin_maintenance_task.html.php | 2 +- modules/organize/js/organize.js | 2 +- .../views/server_add_tree_dialog.html.php | 2 +- modules/tag/js/tag.js | 2 +- themes/admin_default/views/admin.html.php | 2 - themes/default/views/page.html.php | 2 - 12 files changed, 44 insertions(+), 66 deletions(-) delete mode 100644 lib/gallery.reload.js diff --git a/lib/gallery.dialog.js b/lib/gallery.dialog.js index 0efcf120..74c2f20e 100644 --- a/lib/gallery.dialog.js +++ b/lib/gallery.dialog.js @@ -25,9 +25,9 @@ function ajaxify_dialog() { } if (data.result == "success") { if (data.location) { - $.gallery_location(data.location); + window.location = data.location; } else { - $.gallery_reload(); + window.location.reload(); } } } diff --git a/lib/gallery.panel.js b/lib/gallery.panel.js index 26be11ad..022e4878 100644 --- a/lib/gallery.panel.js +++ b/lib/gallery.panel.js @@ -40,9 +40,9 @@ function togglePanel(element, on_success) { if (on_success) { on_success(); } else if (data.location) { - $.gallery_location(data.location); + window.location = data.location; } else { - $.gallery_reload(); + window.location.reload(); } } } diff --git a/lib/gallery.reload.js b/lib/gallery.reload.js deleted file mode 100644 index 2c8752a0..00000000 --- a/lib/gallery.reload.js +++ /dev/null @@ -1,16 +0,0 @@ -/** - * To change this template, choose Tools | Templates - * and open the template in the editor. - */ -(function ($) { - $.gallery_reload = function() { - window.location.reload(); - }; -})(jQuery); - -// Vertically align a block element's content -(function ($) { - $.gallery_location = function(location) { - window.location = location; - }; -})(jQuery); diff --git a/modules/gallery/js/quick.js b/modules/gallery/js/quick.js index 4753808e..fda6470f 100644 --- a/modules/gallery/js/quick.js +++ b/modules/gallery/js/quick.js @@ -67,9 +67,9 @@ var quick_do = function(cont, pane, img) { img.css("margin-top", 0); } } else if (data.location) { - $.gallery_location(data.location); + window.location = data.location; } else if (data.reload) { - $.gallery_reload(); + window.location.reload(); } } }); diff --git a/modules/gallery/tests/xss_data.txt b/modules/gallery/tests/xss_data.txt index 29d223b7..0e118ce7 100644 --- a/modules/gallery/tests/xss_data.txt +++ b/modules/gallery/tests/xss_data.txt @@ -496,25 +496,24 @@ themes/admin_default/views/admin.html.php 20 DIRTY $theme->s themes/admin_default/views/admin.html.php 21 DIRTY $theme->script("jquery.form.js") themes/admin_default/views/admin.html.php 22 DIRTY $theme->script("jquery-ui.js") themes/admin_default/views/admin.html.php 23 DIRTY $theme->script("gallery.common.js") -themes/admin_default/views/admin.html.php 25 DIRTY $theme->script("gallery.reload.js") -themes/admin_default/views/admin.html.php 30 DIRTY $theme->script("gallery.dialog.js") -themes/admin_default/views/admin.html.php 31 DIRTY $theme->script("superfish/js/superfish.js") -themes/admin_default/views/admin.html.php 32 DIRTY $theme->script("jquery.dropshadow.js") -themes/admin_default/views/admin.html.php 33 DIRTY $theme->script("ui.init.js") -themes/admin_default/views/admin.html.php 35 DIRTY $theme->admin_head() -themes/admin_default/views/admin.html.php 38 DIRTY $theme->body_attributes() -themes/admin_default/views/admin.html.php 39 DIRTY $theme->admin_page_top() -themes/admin_default/views/admin.html.php 45 DIRTY $theme->site_status() -themes/admin_default/views/admin.html.php 47 DIRTY $theme->admin_header_top() -themes/admin_default/views/admin.html.php 50 DIRTY $csrf -themes/admin_default/views/admin.html.php 56 DIRTY $theme->admin_menu() -themes/admin_default/views/admin.html.php 58 DIRTY $theme->admin_header_bottom() -themes/admin_default/views/admin.html.php 64 DIRTY $theme->messages() -themes/admin_default/views/admin.html.php 65 DIRTY $content -themes/admin_default/views/admin.html.php 71 DIRTY $sidebar -themes/admin_default/views/admin.html.php 76 DIRTY $theme->admin_footer() -themes/admin_default/views/admin.html.php 78 DIRTY $theme->admin_credits() -themes/admin_default/views/admin.html.php 82 DIRTY $theme->admin_page_bottom() +themes/admin_default/views/admin.html.php 28 DIRTY $theme->script("gallery.dialog.js") +themes/admin_default/views/admin.html.php 29 DIRTY $theme->script("superfish/js/superfish.js") +themes/admin_default/views/admin.html.php 30 DIRTY $theme->script("jquery.dropshadow.js") +themes/admin_default/views/admin.html.php 31 DIRTY $theme->script("ui.init.js") +themes/admin_default/views/admin.html.php 33 DIRTY $theme->admin_head() +themes/admin_default/views/admin.html.php 36 DIRTY $theme->body_attributes() +themes/admin_default/views/admin.html.php 37 DIRTY $theme->admin_page_top() +themes/admin_default/views/admin.html.php 43 DIRTY $theme->site_status() +themes/admin_default/views/admin.html.php 45 DIRTY $theme->admin_header_top() +themes/admin_default/views/admin.html.php 48 DIRTY $csrf +themes/admin_default/views/admin.html.php 54 DIRTY $theme->admin_menu() +themes/admin_default/views/admin.html.php 56 DIRTY $theme->admin_header_bottom() +themes/admin_default/views/admin.html.php 62 DIRTY $theme->messages() +themes/admin_default/views/admin.html.php 63 DIRTY $content +themes/admin_default/views/admin.html.php 69 DIRTY $sidebar +themes/admin_default/views/admin.html.php 74 DIRTY $theme->admin_footer() +themes/admin_default/views/admin.html.php 76 DIRTY $theme->admin_credits() +themes/admin_default/views/admin.html.php 80 DIRTY $theme->admin_page_bottom() themes/admin_default/views/block.html.php 2 DIRTY $id themes/admin_default/views/block.html.php 2 DIRTY $css_id themes/admin_default/views/block.html.php 5 DIRTY $id @@ -602,22 +601,21 @@ themes/default/views/page.html.php 48 DIRTY $theme->s themes/default/views/page.html.php 49 DIRTY $theme->script("jquery.form.js") themes/default/views/page.html.php 50 DIRTY $theme->script("jquery-ui.js") themes/default/views/page.html.php 51 DIRTY $theme->script("gallery.common.js") -themes/default/views/page.html.php 53 DIRTY $theme->script("gallery.reload.js") -themes/default/views/page.html.php 58 DIRTY $theme->script("gallery.dialog.js") -themes/default/views/page.html.php 59 DIRTY $theme->script("gallery.form.js") -themes/default/views/page.html.php 60 DIRTY $theme->script("superfish/js/superfish.js") -themes/default/views/page.html.php 61 DIRTY $theme->script("jquery.localscroll.js") -themes/default/views/page.html.php 62 DIRTY $theme->script("ui.init.js") -themes/default/views/page.html.php 66 DIRTY $theme->script("jquery.scrollTo.js") -themes/default/views/page.html.php 67 DIRTY $theme->script("gallery.show_full_size.js") -themes/default/views/page.html.php 69 DIRTY $theme->script("flowplayer.js") -themes/default/views/page.html.php 72 DIRTY $theme->head() -themes/default/views/page.html.php 75 DIRTY $theme->body_attributes() -themes/default/views/page.html.php 76 DIRTY $theme->page_top() -themes/default/views/page.html.php 78 DIRTY $theme->site_status() -themes/default/views/page.html.php 86 DIRTY $theme->messages() -themes/default/views/page.html.php 87 DIRTY $content -themes/default/views/page.html.php 101 DIRTY $theme->page_bottom() +themes/default/views/page.html.php 56 DIRTY $theme->script("gallery.dialog.js") +themes/default/views/page.html.php 57 DIRTY $theme->script("gallery.form.js") +themes/default/views/page.html.php 58 DIRTY $theme->script("superfish/js/superfish.js") +themes/default/views/page.html.php 59 DIRTY $theme->script("jquery.localscroll.js") +themes/default/views/page.html.php 60 DIRTY $theme->script("ui.init.js") +themes/default/views/page.html.php 64 DIRTY $theme->script("jquery.scrollTo.js") +themes/default/views/page.html.php 65 DIRTY $theme->script("gallery.show_full_size.js") +themes/default/views/page.html.php 67 DIRTY $theme->script("flowplayer.js") +themes/default/views/page.html.php 70 DIRTY $theme->head() +themes/default/views/page.html.php 73 DIRTY $theme->body_attributes() +themes/default/views/page.html.php 74 DIRTY $theme->page_top() +themes/default/views/page.html.php 76 DIRTY $theme->site_status() +themes/default/views/page.html.php 84 DIRTY $theme->messages() +themes/default/views/page.html.php 85 DIRTY $content +themes/default/views/page.html.php 99 DIRTY $theme->page_bottom() themes/default/views/pager.html.php 13 DIRTY $url themes/default/views/pager.html.php 20 DIRTY $previous_page themes/default/views/pager.html.php 20 DIRTY $url diff --git a/modules/gallery/views/admin_maintenance_show_log.html.php b/modules/gallery/views/admin_maintenance_show_log.html.php index ac593de7..9d850986 100644 --- a/modules/gallery/views/admin_maintenance_show_log.html.php +++ b/modules/gallery/views/admin_maintenance_show_log.html.php @@ -1,7 +1,7 @@
                      diff --git a/modules/organize/js/organize.js b/modules/organize/js/organize.js index 0a7576b0..89549954 100644 --- a/modules/organize/js/organize.js +++ b/modules/organize/js/organize.js @@ -58,7 +58,7 @@ $("#gOrganizeDialog #gMicroThumbDone").click(_dialog_close); $("#gOrganizeDialog").bind("organize_close", function(target) { - $.gallery_reload(); + document.location.reload(); }); $(".gBranchText span").click(_collapse_or_expanded_tree); diff --git a/modules/server_add/views/server_add_tree_dialog.html.php b/modules/server_add/views/server_add_tree_dialog.html.php index 8dfd2c38..21952849 100644 --- a/modules/server_add/views/server_add_tree_dialog.html.php +++ b/modules/server_add/views/server_add_tree_dialog.html.php @@ -34,7 +34,7 @@ - diff --git a/modules/tag/js/tag.js b/modules/tag/js/tag.js index 564de393..765c2a35 100644 --- a/modules/tag/js/tag.js +++ b/modules/tag/js/tag.js @@ -59,7 +59,7 @@ function editInPlace(element) { closeEditInPlaceForms(); // close form $("#gTag-" + data.tag_id).text(data.new_tagname); // update tagname console.log(data); - $.gallery_reload(); + window.location.reload(); } } }); diff --git a/themes/admin_default/views/admin.html.php b/themes/admin_default/views/admin.html.php index 63fc45b5..d27f9260 100644 --- a/themes/admin_default/views/admin.html.php +++ b/themes/admin_default/views/admin.html.php @@ -21,8 +21,6 @@ script("jquery.form.js") ?> script("jquery-ui.js") ?> script("gallery.common.js") ?> - - script("gallery.reload.js") ?> \ No newline at end of file -- cgit v1.2.3 From 6e4023a7207b721694403f38d6afb7a507468498 Mon Sep 17 00:00:00 2001 From: Bharat Mediratta Date: Thu, 6 Aug 2009 16:16:11 -0700 Subject: Fix indentation. --- modules/organize/js/organize.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/organize/js/organize.js b/modules/organize/js/organize.js index e4d4a9a2..4c45b007 100644 --- a/modules/organize/js/organize.js +++ b/modules/organize/js/organize.js @@ -12,7 +12,7 @@ $("#gDialog #gMicroThumbDone").click(function(event) { $("#gDialog").dialog("close"); - window.location.reload(); + window.location.reload(); }); $(".gBranchText span").click($.organize.collapse_or_expand_tree); -- cgit v1.2.3 From 0fc96621d55e1e6b3b5f7f84760a39ff06f0e641 Mon Sep 17 00:00:00 2001 From: Bharat Mediratta Date: Wed, 5 Aug 2009 22:32:41 -0700 Subject: Don't show the ajaxy login link in the top right corner if we're on the login page itself. --- modules/user/helpers/user_theme.php | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/modules/user/helpers/user_theme.php b/modules/user/helpers/user_theme.php index 69042aed..8de2d248 100644 --- a/modules/user/helpers/user_theme.php +++ b/modules/user/helpers/user_theme.php @@ -19,8 +19,10 @@ */ class user_theme_Core { static function header_top($theme) { - $view = new View("login.html"); - $view->user = user::active(); - return $view->render(); + if ($theme->page_type != "login") { + $view = new View("login.html"); + $view->user = user::active(); + return $view->render(); + } } } -- cgit v1.2.3 From 93c0dffab3ba3631c9ebf4693571bd38e5613d1c Mon Sep 17 00:00:00 2001 From: Tim Almdal Date: Thu, 6 Aug 2009 09:46:39 -0700 Subject: Remove the complicated calculation to determine the height of the micro thumb grid, by setting all the parent elements to 100% in the css and then subtract the height of the button bar --- modules/organize/css/organize.css | 11 +++++++++- modules/organize/js/organize.js | 43 ++++++++++++++++----------------------- 2 files changed, 27 insertions(+), 27 deletions(-) diff --git a/modules/organize/css/organize.css b/modules/organize/css/organize.css index 0a23a6bf..56ecc309 100644 --- a/modules/organize/css/organize.css +++ b/modules/organize/css/organize.css @@ -7,6 +7,11 @@ #gOrganize { overflow: hidden; + height: 100%; +} + +#gOrganize #bd { + height: 100%; } #gOrganize .yui-u { @@ -22,16 +27,20 @@ width: 75%; } +#gOrganizeDetail { + height: 100%; +} + #gMessage .gInfo { font-weight: bold; padding-left: 2em; } - /******************************************************************* * Album Tree styling */ #gOrganizeTreeContainer { + height: 100%; overflow: auto; margin: 0 !important; padding: 0 !important; diff --git a/modules/organize/js/organize.js b/modules/organize/js/organize.js index 89549954..6a65bfa2 100644 --- a/modules/organize/js/organize.js +++ b/modules/organize/js/organize.js @@ -1,54 +1,45 @@ (function($) { - $.fn.organize = function(options) { + $.fn.organize = function() { var size = $.getViewportSize(); var height = size.height() - 100; // Leave 50 pixels on the top and bottom of the dialog var width = size.width() - 100; // Leave 50 pixels on the left and right of the dialog - var opts = $.extend({}, $.fn.organize.defaults, {width: width, height: height}, options); return this.each(function() { $(this).click(function(event) { var href = event.target.href; - var size = $.getViewportSize(); $("body").append('
                      '); - $("#gOrganizeDialog").dialog(opts); + $("#gOrganizeDialog").dialog({ + autoOpen: false, + modal: true, + resizable: false, + width: width, + height: height, + position: "center", + close: function () { + $("#gOrganizeDialog").trigger("organize_close"); + $("#gOrganizeDialog").dialog("destroy").remove(); + }, + zIndex: 75 + }); $.get(href, _init); return false; }); }); }; - $.fn.organize.defaults = { - autoOpen: false, - modal: true, - resizable: false, - minWidth: 600, - minHeight: 500, - position: "center", - close: function () { - $("#gOrganizeDialog").trigger("organize_close"); - $("#gOrganizeDialog").dialog("destroy").remove(); - }, - zIndex: 75 - }; - /** * Dynamically initialize the organize dialog when it is displayed */ function _init(data) { - // Deal with ui.jquery bug: http://dev.jqueryui.com/ticket/4475 + // Deal with ui.jquery bug: http://dev.jqueryui.com/ticket/4475 (target 1.8?) $(".sf-menu li.sfHover ul").css("z-index", 70); $("#gOrganizeDialog").html(data); $("#gOrganizeDialog").dialog("open"); - var heightMicroThumbPanel = $("#gOrganizeDialog").innerHeight(); - heightMicroThumbPanel -= 2 * parseFloat($("#gOrganizeDialog").css("padding-bottom")); - heightMicroThumbPanel = Math.floor(heightMicroThumbPanel - 10 - $("#gMessage").outerHeight()); - $("#gOrganizeTreeContainer").height(heightMicroThumbPanel); - - heightMicroThumbPanel -= $("#gOrganizeEditDrawerHandle").outerHeight(); - $("#gMicroThumbPanel").height(heightMicroThumbPanel); + var height = $("#gOrganizeDetail").innerHeight(); + $("#gMicroThumbPanel").height(height - $("#gOrganizeEditDrawerHandle").outerHeight()); if ($("#gOrganizeDialog h1").length) { $("#gOrganizeDialog").dialog('option', 'title', $("#gOrganizeDialog h1:eq(0)").html()); -- cgit v1.2.3 From 362b4d70f72fa6baed15bd323a2ca5deea7d6ab3 Mon Sep 17 00:00:00 2001 From: Tim Almdal Date: Thu, 6 Aug 2009 10:03:38 -0700 Subject: Remove 6 more lines by removing the generalization of the close dialog processing --- modules/organize/js/organize.js | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/modules/organize/js/organize.js b/modules/organize/js/organize.js index 6a65bfa2..3e58f3f3 100644 --- a/modules/organize/js/organize.js +++ b/modules/organize/js/organize.js @@ -17,9 +17,9 @@ height: height, position: "center", close: function () { - $("#gOrganizeDialog").trigger("organize_close"); $("#gOrganizeDialog").dialog("destroy").remove(); - }, + document.location.reload(); + }, zIndex: 75 }); $.get(href, _init); @@ -47,20 +47,14 @@ $("#gOrganizeDialog").dialog('option', 'title', $("#gOrganizeDialog fieldset legend:eq(0)").html()); } - $("#gOrganizeDialog #gMicroThumbDone").click(_dialog_close); - $("#gOrganizeDialog").bind("organize_close", function(target) { - document.location.reload(); + $("#gOrganizeDialog #gMicroThumbDone").click(function(event) { + $("#gOrganizeDialog").dialog("close"); }); $(".gBranchText span").click(_collapse_or_expanded_tree); $(".gBranchText").click(_setContents); }; - function _dialog_close(event) { - event.preventDefault(); - $("#gOrganizeDialog").dialog("close"); - }; - /** * Open or close a branch. If the children is a div placeholder, replace with
                        */ -- cgit v1.2.3 From 87598288f493cadcc5c273dd7305ad579d251678 Mon Sep 17 00:00:00 2001 From: Bharat Mediratta Date: Thu, 6 Aug 2009 20:38:42 -0700 Subject: If we fail the version check, at least show the version of PHP that the server is using. --- index.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/index.php b/index.php index 7def7d16..d0e12cfc 100644 --- a/index.php +++ b/index.php @@ -21,7 +21,8 @@ define("IN_PRODUCTION", true); // Gallery requires PHP 5.2+ -version_compare(PHP_VERSION, "5.2.3", "<") and exit("Gallery requires PHP 5.2.3 or newer."); +version_compare(PHP_VERSION, "5.2.3", "<") and + exit("Gallery requires PHP 5.2.3 or newer (you're using " . PHP_VERSION . ")"); // Gallery requires short_tags to be on !ini_get("short_open_tag") and exit("Gallery requires short_open_tag to be on."); -- cgit v1.2.3 From d3f46436999b7326e88986daa5a99516430dbf15 Mon Sep 17 00:00:00 2001 From: Bharat Mediratta Date: Thu, 6 Aug 2009 21:02:22 -0700 Subject: * Rename setContents -> show_album to be consistent style wise (no camel caps) and more explicit about what it's doing. * use toggleClass() to simplify the +/- css management. --- modules/organize/js/organize.js | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/modules/organize/js/organize.js b/modules/organize/js/organize.js index 4c45b007..d2006c27 100644 --- a/modules/organize/js/organize.js +++ b/modules/organize/js/organize.js @@ -16,26 +16,22 @@ }); $(".gBranchText span").click($.organize.collapse_or_expand_tree); - $(".gBranchText").click($.organize.setContents); + $(".gBranchText").click($.organize.show_album); }, /** - * Open or close a branch. If the children is a div placeholder, replace with
                          + * Open or close a branch. */ - collapse_or_expand_tree: function (event) { + collapse_or_expand_tree: function(event) { event.stopPropagation(); - if ($(event.currentTarget).hasClass("ui-icon-minus")) { - $(event.currentTarget).removeClass("ui-icon-minus").addClass("ui-icon-plus"); - } else { - $(event.currentTarget).removeClass("ui-icon-plus").addClass("ui-icon-minus"); - } + $(event.currentTarget).toggleClass("ui-icon-minus").toggleClass("ui-icon-plus"); $("#gOrganizeChildren-" + $(event.currentTarget).attr("ref")).toggle(); }, /** * When the text of a selection is clicked, then show that albums contents */ - setContents: function(event) { + show_album: function(event) { event.preventDefault(); if ($(event.currentTarget).hasClass("gBranchSelected")) { return; -- cgit v1.2.3 From a245c57400398d2b4b1c2aea94f590a9c0a7d8a8 Mon Sep 17 00:00:00 2001 From: Bharat Mediratta Date: Thu, 6 Aug 2009 21:36:17 -0700 Subject: Further streamline the code. Organize_Controller: * Remove unnecessary constants * Rename index() to dialog() * Simplify _get_micro_thumb_grid organize.js: * Move sizing code in here from organize_dialog.html.php organize_dialog.html.php: * Move CSS and JS links in here so that we only load them when we need them. * Move sizing code into organize.js organize_thumb_grid.html.php: * Move pagination logic in here, since it's view centric * Collapse the css class determination code and inline it --- modules/organize/controllers/organize.php | 22 +++++---------- modules/organize/helpers/organize_event.php | 2 +- modules/organize/helpers/organize_theme.php | 27 ------------------- modules/organize/js/organize.js | 6 +++++ modules/organize/views/organize_dialog.html.php | 9 +++---- .../organize/views/organize_thumb_grid.html.php | 31 +++++++++++----------- modules/organize/views/organize_tree.html.php | 2 -- 7 files changed, 33 insertions(+), 66 deletions(-) delete mode 100644 modules/organize/helpers/organize_theme.php diff --git a/modules/organize/controllers/organize.php b/modules/organize/controllers/organize.php index 95d71e9c..3a81ef4f 100644 --- a/modules/organize/controllers/organize.php +++ b/modules/organize/controllers/organize.php @@ -18,10 +18,7 @@ * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ class Organize_Controller extends Controller { - private static $_MICRO_THUMB_SIZE = 90; - private static $_MICRO_THUMB_PADDING = 10; - - function index($item_id) { + function dialog($item_id) { $item = ORM::factory("item", $item_id); $root = $item->id == 1 ? $item : ORM::factory("item", 1); access::required("view", $item); @@ -36,26 +33,21 @@ class Organize_Controller extends Controller { $parents[$item->id] = 1; $v->album_tree = $this->_tree($root, $parents); - $v->micro_thumb_grid = $this->_get_micro_thumb_grid($item); + $v->micro_thumb_grid = $this->_get_micro_thumb_grid($item, 0); print $v; } - function content($item_id, $offset=0) { + function content($item_id, $offset) { $item = ORM::factory("item", $item_id); access::required("view", $item); access::required("edit", $item); - - $v = $this->_get_micro_thumb_grid($item, $offset); - print $v->__toString(); + print $this->_get_micro_thumb_grid($item, $offset); } - private function _get_micro_thumb_grid($item, $offset=0) { + private function _get_micro_thumb_grid($item, $offset) { $v = new View("organize_thumb_grid.html"); - $v->item_id = $item->id; - $v->children = $item->children(25, $offset); - $v->thumbsize = self::$_MICRO_THUMB_SIZE; - $v->offset = $offset + 25; - + $v->item = $item; + $v->offset = $offset; return $v; } diff --git a/modules/organize/helpers/organize_event.php b/modules/organize/helpers/organize_event.php index 887d9c2d..7d6b3e24 100644 --- a/modules/organize/helpers/organize_event.php +++ b/modules/organize/helpers/organize_event.php @@ -27,7 +27,7 @@ class organize_event_Core { ->id("organize") ->label(t("Organize Album")) ->css_id("gOrganizeLink") - ->url(url::site("organize/index/{$item->id}"))); + ->url(url::site("organize/dialog/{$item->id}"))); } } } diff --git a/modules/organize/helpers/organize_theme.php b/modules/organize/helpers/organize_theme.php deleted file mode 100644 index 0fd117c3..00000000 --- a/modules/organize/helpers/organize_theme.php +++ /dev/null @@ -1,27 +0,0 @@ -item()) && access::can("edit", $theme->item())) { - $theme->script("organize.js"); - $theme->css("organize.css"); - } - } -} diff --git a/modules/organize/js/organize.js b/modules/organize/js/organize.js index d2006c27..6b4a5934 100644 --- a/modules/organize/js/organize.js +++ b/modules/organize/js/organize.js @@ -4,6 +4,12 @@ * Dynamically initialize the organize dialog when it is displayed */ init: function(data) { + // Resize with 50 pixels padding all around + var size = $.getViewportSize(); + $("#gDialog").dialog("option", "height", size.height() - 100) + .dialog("option", "width", size.width() - 100) + .dialog("option", "position", "center"); + // Deal with ui.jquery bug: http://dev.jqueryui.com/ticket/4475 (target 1.8?) $(".sf-menu li.sfHover ul").css("z-index", 70); diff --git a/modules/organize/views/organize_dialog.html.php b/modules/organize/views/organize_dialog.html.php index 11ce0a37..6001e038 100644 --- a/modules/organize/views/organize_dialog.html.php +++ b/modules/organize/views/organize_dialog.html.php @@ -1,4 +1,5 @@ +" />

                          p::purify($title))) ?>

                          @@ -38,13 +39,9 @@
                          + \ No newline at end of file + diff --git a/modules/organize/views/organize_thumb_grid.html.php b/modules/organize/views/organize_thumb_grid.html.php index e6b7aec0..0d54c5c8 100644 --- a/modules/organize/views/organize_thumb_grid.html.php +++ b/modules/organize/views/organize_thumb_grid.html.php @@ -1,19 +1,20 @@ - $child): ?> - - is_album()): ?> - - -
                        • - thumb_img(array("class" => "gThumbnail"), $thumbsize, true) ?> -
                        • +children(25, $offset) as $child): ?> +
                        • " + ref="id ?>"> + thumb_img(array("class" => "gThumbnail"), 90, true) ?> +
                        • -= 25): ?> + +children_count() > $offset): ?> - \ No newline at end of file + diff --git a/modules/organize/views/organize_tree.html.php b/modules/organize/views/organize_tree.html.php index 280bdc5f..99b0dc1a 100644 --- a/modules/organize/views/organize_tree.html.php +++ b/modules/organize/views/organize_tree.html.php @@ -1,6 +1,5 @@
                        • -
                          gBranchText">
                        - -- cgit v1.2.3 From 2f3cef44cc87bfc81778dd4ff3ad6d7b94a514b0 Mon Sep 17 00:00:00 2001 From: Tim Almdal Date: Fri, 7 Aug 2009 06:15:07 -0700 Subject: Refactor the gallery.panel.js as a jQuery widget. --- lib/gallery.panel.js | 116 ++++++++++++++++++------------------- themes/admin_default/js/ui.init.js | 3 +- 2 files changed, 57 insertions(+), 62 deletions(-) diff --git a/lib/gallery.panel.js b/lib/gallery.panel.js index 022e4878..98d78d2a 100644 --- a/lib/gallery.panel.js +++ b/lib/gallery.panel.js @@ -1,62 +1,58 @@ -/** - * Fire togglePanel() and prevent links from opening - * @see togglePanel() - */ -function handlePanelEvent(event) { - togglePanel(event.currentTarget); - event.preventDefault(); -} +(function($) { + $.widget("ui.galleryPanel", { + _init: function() { + var self = this; + this.element.click(function(event) { + event.preventDefault(); + var element = event.currentTarget; + var parent = $(element).parent().parent(); + var sHref = $(element).attr("href"); + var parentClass = $(parent).attr("class"); + var ePanel = ""; -function togglePanel(element, on_success) { - var parent = $(element).parent().parent(); - var sHref = $(element).attr("href"); - var parentClass = $(parent).attr("class"); - var ePanel = ""; + if ($("#gPanel").length) { + $("#gPanel").slideUp("slow").remove(); + if ($(element).attr("orig_text")) { + $(element).children(".gButtonText").text($(element).attr("orig_text")); + } + } else { + $(parent).after(ePanel); + $("#gPanel td").html(sHref); + $.get(sHref, function(data) { + $("#gPanel td").html(data); + self._ajaxify_panel(); + if ($(element).attr("open_text")) { + $(element).attr("orig_text", $(element).children(".gButtonText").text()); + $(element).children(".gButtonText").text($(element).attr("open_text")); + } + $("#gPanel").addClass(parentClass).show().slideDown("slow"); + }); + } + return false; + }); + }, - if ($("#gPanel").length) { - $("#gPanel").slideUp("slow"); - $("#gPanel *").remove(); - $("#gPanel").remove(); - if ($(element).attr("orig_text")) { - $(element).children(".gButtonText").text($(element).attr("orig_text")); - } - //togglePanel(element, on_success); - } else { - $(parent).after(ePanel); - //showLoading("#here"); - $("#gPanel td").html(sHref); - $("#gPanel").addClass(parentClass).show().slideDown("slow"); - $.get(sHref, function(data) { - $("#gPanel td").html(data); - ajaxify_panel = function() { - $("#gPanel td form").ajaxForm({ - dataType: "json", - success: function(data) { - if (data.form) { - $("#gPanel td form").replaceWith(data.form); - ajaxify_panel(); - } - if (data.result == "success") { - if (on_success) { - on_success(); - } else if (data.location) { - window.location = data.location; - } else { - window.location.reload(); - } - } - } - }); - if ($("#gPanel td").hasClass("gLoadingLarge")) { - showLoading("#gPanel td"); - } - }; - ajaxify_panel(); - if ($(element).attr("open_text")) { - $(element).attr("orig_text", $(element).children(".gButtonText").text()); - $(element).children(".gButtonText").text($(element).attr("open_text")); - } - }); - } - return false; -} + _ajaxify_panel: function () { + var self = this; + $("#gPanel td form").ajaxForm({ + dataType: "json", + success: function(data) { + if (data.form) { + $("#gPanel td form").replaceWith(data.form); + self._ajaxify_panel(); + } + if (data.result == "success") { + self._trigger("success", null, {}); + if (data.location) { + window.location = data.location; + } else { + window.location.reload(); + } + } + } + }); + }, + + success: function(event, ui) {} + }); + })(jQuery); diff --git a/themes/admin_default/js/ui.init.js b/themes/admin_default/js/ui.init.js index 06cc1cd5..63b74300 100644 --- a/themes/admin_default/js/ui.init.js +++ b/themes/admin_default/js/ui.init.js @@ -1,5 +1,4 @@ $(document).ready(function(){ - // Initialize Superfish menus $("#gSiteAdminMenu ul.gMenu").addClass("sf-menu"); $("ul.gMenu").addClass("sf-menu"); @@ -21,7 +20,7 @@ $(document).ready(function(){ $(".gDialogLink").bind("click", handleDialogEvent); // Initialize panels - $(".gPanelLink").bind("click", handlePanelEvent); + $(".gPanelLink").galleryPanel(); if ($("#gPhotoStream").length) { // Vertically align thumbs in photostream -- cgit v1.2.3 From 6abcc06e21d0b7827e395f6a6eef673f83d4d0ec Mon Sep 17 00:00:00 2001 From: Tim Almdal Date: Fri, 7 Aug 2009 21:15:07 +0800 Subject: Refactor the gallery.panel.js as a jQuery widget. Signed-off-by: Tim Almdal --- lib/gallery.panel.js | 116 ++++++++++++++++++------------------- themes/admin_default/js/ui.init.js | 3 +- 2 files changed, 57 insertions(+), 62 deletions(-) diff --git a/lib/gallery.panel.js b/lib/gallery.panel.js index 022e4878..98d78d2a 100644 --- a/lib/gallery.panel.js +++ b/lib/gallery.panel.js @@ -1,62 +1,58 @@ -/** - * Fire togglePanel() and prevent links from opening - * @see togglePanel() - */ -function handlePanelEvent(event) { - togglePanel(event.currentTarget); - event.preventDefault(); -} +(function($) { + $.widget("ui.galleryPanel", { + _init: function() { + var self = this; + this.element.click(function(event) { + event.preventDefault(); + var element = event.currentTarget; + var parent = $(element).parent().parent(); + var sHref = $(element).attr("href"); + var parentClass = $(parent).attr("class"); + var ePanel = ""; -function togglePanel(element, on_success) { - var parent = $(element).parent().parent(); - var sHref = $(element).attr("href"); - var parentClass = $(parent).attr("class"); - var ePanel = ""; + if ($("#gPanel").length) { + $("#gPanel").slideUp("slow").remove(); + if ($(element).attr("orig_text")) { + $(element).children(".gButtonText").text($(element).attr("orig_text")); + } + } else { + $(parent).after(ePanel); + $("#gPanel td").html(sHref); + $.get(sHref, function(data) { + $("#gPanel td").html(data); + self._ajaxify_panel(); + if ($(element).attr("open_text")) { + $(element).attr("orig_text", $(element).children(".gButtonText").text()); + $(element).children(".gButtonText").text($(element).attr("open_text")); + } + $("#gPanel").addClass(parentClass).show().slideDown("slow"); + }); + } + return false; + }); + }, - if ($("#gPanel").length) { - $("#gPanel").slideUp("slow"); - $("#gPanel *").remove(); - $("#gPanel").remove(); - if ($(element).attr("orig_text")) { - $(element).children(".gButtonText").text($(element).attr("orig_text")); - } - //togglePanel(element, on_success); - } else { - $(parent).after(ePanel); - //showLoading("#here"); - $("#gPanel td").html(sHref); - $("#gPanel").addClass(parentClass).show().slideDown("slow"); - $.get(sHref, function(data) { - $("#gPanel td").html(data); - ajaxify_panel = function() { - $("#gPanel td form").ajaxForm({ - dataType: "json", - success: function(data) { - if (data.form) { - $("#gPanel td form").replaceWith(data.form); - ajaxify_panel(); - } - if (data.result == "success") { - if (on_success) { - on_success(); - } else if (data.location) { - window.location = data.location; - } else { - window.location.reload(); - } - } - } - }); - if ($("#gPanel td").hasClass("gLoadingLarge")) { - showLoading("#gPanel td"); - } - }; - ajaxify_panel(); - if ($(element).attr("open_text")) { - $(element).attr("orig_text", $(element).children(".gButtonText").text()); - $(element).children(".gButtonText").text($(element).attr("open_text")); - } - }); - } - return false; -} + _ajaxify_panel: function () { + var self = this; + $("#gPanel td form").ajaxForm({ + dataType: "json", + success: function(data) { + if (data.form) { + $("#gPanel td form").replaceWith(data.form); + self._ajaxify_panel(); + } + if (data.result == "success") { + self._trigger("success", null, {}); + if (data.location) { + window.location = data.location; + } else { + window.location.reload(); + } + } + } + }); + }, + + success: function(event, ui) {} + }); + })(jQuery); diff --git a/themes/admin_default/js/ui.init.js b/themes/admin_default/js/ui.init.js index 06cc1cd5..63b74300 100644 --- a/themes/admin_default/js/ui.init.js +++ b/themes/admin_default/js/ui.init.js @@ -1,5 +1,4 @@ $(document).ready(function(){ - // Initialize Superfish menus $("#gSiteAdminMenu ul.gMenu").addClass("sf-menu"); $("ul.gMenu").addClass("sf-menu"); @@ -21,7 +20,7 @@ $(document).ready(function(){ $(".gDialogLink").bind("click", handleDialogEvent); // Initialize panels - $(".gPanelLink").bind("click", handlePanelEvent); + $(".gPanelLink").galleryPanel(); if ($("#gPhotoStream").length) { // Vertically align thumbs in photostream -- cgit v1.2.3 From bc6c5207be18cf978cf4e8f5c22a3adbb8254476 Mon Sep 17 00:00:00 2001 From: Tim Almdal Date: Fri, 7 Aug 2009 08:58:57 -0700 Subject: Refactor the gallery dialog into a jQuery widget --- lib/gallery.common.js | 27 ++- lib/gallery.dialog.js | 252 ++++++++++----------- modules/gallery/views/after_install.html.php | 2 +- .../views/server_add_tree_dialog.html.php | 5 +- modules/tag/js/tag.js | 2 +- modules/user/views/admin_users.html.php | 2 +- themes/admin_default/js/ui.init.js | 2 +- themes/default/js/ui.init.js | 2 +- 8 files changed, 155 insertions(+), 139 deletions(-) diff --git a/lib/gallery.common.js b/lib/gallery.common.js index 1eaa6db2..e063462e 100644 --- a/lib/gallery.common.js +++ b/lib/gallery.common.js @@ -2,17 +2,15 @@ * To change this template, choose Tools | Templates * and open the template in the editor. */ -(function () { +(function ($) { $.fn.showMessage = function(message) { return this.each(function(i){ $(this).effect("highlight", {"color": "white"}, 3000); $(this).animate({opacity: 1.0}, 6000); }); }; -})(jQuery); // Vertically align a block element's content -(function () { $.fn.vAlign = function(container) { return this.each(function(i){ if (container == null) { @@ -26,10 +24,8 @@ $(el).css('margin-top', nh); }); }; -})(jQuery); // Get the viewport size -(function () { $.getViewportSize = function() { return { width : function() { @@ -40,4 +36,25 @@ } }; }; + + /** + * Toggle the processing indicator, both large and small + * @param elementID Target ID, including #, to apply .gLoadingSize + */ + $.fn.showLoading = function() { + return this.each(function(i){ + var size; + switch ($(this).attr("id")) { + case "#gDialog": + case "#gPanel": + size = "Large"; + break; + default: + size = "Small"; + break; + } + $(this).toggleClass("gLoading" + size); + }); + }; + })(jQuery); diff --git a/lib/gallery.dialog.js b/lib/gallery.dialog.js index 74c2f20e..7e0ba1b4 100644 --- a/lib/gallery.dialog.js +++ b/lib/gallery.dialog.js @@ -1,140 +1,136 @@ -/** - * Fire openDialog() and prevent links from opening - * @see openDialog() - */ -function handleDialogEvent(event) { - var target = event.currentTarget; - if (!target) { - target = event.srcElement; - } - openDialog(target); - event.preventDefault(); -} +(function($) { + $.widget("ui.galleryDialog", { + _init: function() { + var self = this; + this.element.click(function(event){ + event.preventDefault(); + var element = event.currentTarget; + var sHref = $(element).attr("href"); + var sTitle = $(element).attr("title"); + var eDialog = '
                        '; -function ajaxify_dialog() { - $("#gDialog form").ajaxForm({ - dataType: "json", - success: function(data) { - if (data.form) { - $("#gDialog form").replaceWith(data.form); - ajaxify_dialog(); - on_form_loaded(); - if (typeof data.reset == 'function') { - eval(data.reset + '()'); - } - } - if (data.result == "success") { - if (data.location) { - window.location = data.location; - } else { - window.location.reload(); - } - } - } - }); -}; + $("body").append(eDialog); + + if (!self.options.close) { + self.options.close = self.closeDialog; + } + $("#gDialog").dialog(self.options); -/** - * Display modal dialogs, populate dialog with trigger link's href - * @requires ui.core - * @requires ui.draggable - * @requires ui.resizable - * @requires ui.dialog - * @see handleDialogEvent() - * @see showLoading() - */ -function openDialog(element) { - var sHref = $(element).attr("href"); - var sTitle = $(element).attr("title"); - var eDialog = '
                        '; - var dialogWidth; + $("#gDialog").showLoading(); - $("body").append(eDialog); + $.get(sHref, function(data) { + $("#gDialog").html(data).showLoading(); - $("#gDialog").dialog({ - autoOpen: false, - autoResize: true, - modal: true, - resizable: false, - close: closeDialog - }); + if ($("#gDialog form").length) { + self._trigger("form_loaded", null, $("#gDialog form")); + } + self._layout(); - showLoading("#gDialog"); + $("#gDialog").dialog("open"); + // Remove titlebar for progress dialogs or set title + if ($("#gDialog #gProgress").length) { + $(".ui-dialog-titlebar").remove(); + } else if ($("#gDialog h1").length) { + $("#gDialog").dialog('option', 'title', $("#gDialog h1:eq(0)").html()); + } else if ($("#gDialog fieldset legend").length) { + $("#gDialog").dialog('option', 'title', $("#gDialog fieldset legend:eq(0)").html()); + } - $.get(sHref, function(data) { - showLoading("#gDialog"); - $("#gDialog").html(data); - var dialogHeight = $("#gDialog").height(); - var cssWidth = new String($("#gDialog form").css("width")); - var childWidth = cssWidth.replace(/[^0-9]/g,""); - if ($("#gDialog iframe").length) { - dialogWidth = $(window).width() - 100; - // Set the iframe width and height - $("#gDialog iframe").width("100%"); - $("#gDialog iframe").height($(window).height() - 100); - } else if (childWidth == "" || childWidth > 300) { - dialogWidth = 500; - } - $("#gDialog").dialog('option', 'width', dialogWidth); + if ($("#gDialog form").length) { + self._ajaxify_dialog(); + } + }); + $("#gDialog").dialog("option", "self", self); + return false; + }); + }, - on_form_loaded(); + destroy: function() { + if ($("#gDialog form").length) { + this._trigger("form_closing", null, $("#gDialog form")); + } + this._trigger("dialog_closing", null, $("#gDialog")); - $("#gDialog").dialog("open"); - // Remove titlebar for progress dialogs or set title - if ($("#gDialog #gProgress").length) { - $(".ui-dialog-titlebar").remove(); - } else if ($("#gDialog h1").length) { - $("#gDialog").dialog('option', 'title', $("#gDialog h1:eq(0)").html()); - } else if ($("#gDialog fieldset legend").length) { - $("#gDialog").dialog('option', 'title', $("#gDialog fieldset legend:eq(0)").html()); - } + $("#gDialog").dialog("destroy").remove(); + }, + + _layout: function() { + var dialogWidth; + var dialogHeight = $("#gDialog").height(); + var cssWidth = new String($("#gDialog form").css("width")); + var childWidth = cssWidth.replace(/[^0-9]/g,""); + if ($("#gDialog iframe").length) { + dialogWidth = $(window).width() - 100; + // Set the iframe width and height + $("#gDialog iframe").width("100%").height($(window).height() - 100); + } else if (childWidth == "" || childWidth > 300) { + dialogWidth = 500; + } + $("#gDialog").dialog('option', 'width', dialogWidth); + }, + + form_loaded: function event(event, ui) { + // Should be defined (and localized) in the theme + MSG_CANCEL = MSG_CANCEL || 'Cancel'; + var eCancel = '' + MSG_CANCEL + ''; + if ($("#gDialog .submit").length) { + $("#gDialog .submit").addClass("ui-state-default ui-corner-all"); + $("#gDialog .submit").parent().append(eCancel); + $("#gDialog .gCancel").click(function(event) { + $("gDialog").dialog("close"); + event.preventDefault(); + }); + } + $("#gDialog .ui-state-default").hover( + function() { + $(this).addClass("ui-state-hover"); + }, + function() { + $(this).removeClass("ui-state-hover"); + } + ); + }, - ajaxify_dialog(); - }); - return false; -} + closeDialog: function (event, ui) { + var self = $("#gDialog").dialog("option", "self"); + self.destroy(); + }, -function on_form_loaded() { - // Should be defined (and localized) in the theme - MSG_CANCEL = MSG_CANCEL || 'Cancel'; - var eCancel = '' + MSG_CANCEL + ''; - if ($("#gDialog .submit").length) { - $("#gDialog .submit").addClass("ui-state-default ui-corner-all"); - $("#gDialog .submit").parent().append(eCancel); - } - $("#gDialog").dialog("option", "form", $("#gDialog form")); - $("#gDialog .ui-state-default").hover( - function() { - $(this).addClass("ui-state-hover"); - }, - function() { - $(this).removeClass("ui-state-hover"); - } - ); -} + _ajaxify_dialog: function() { + var self = this; + $("#gDialog form").ajaxForm({ + dataType: "json", + success: function(data) { + if (data.form) { + $("#gDialog form").replaceWith(data.form); + self._ajaxify_dialog(); + self._trigger("form_loaded", null, $("#gDialog form")); + if (typeof data.reset == 'function') { + eval(data.reset + '()'); + } + } + if (data.result == "success") { + if (data.location) { + window.location = data.location; + } else { + window.location.reload(); + } + } + } + }); + }, -function closeDialog() { - var form = $("#gDialog").dialog("option", "form"); - if (form != null) { - $("#gDialog").dialog("option", "form").trigger("form_closing"); - } - $("#gDialog").dialog("destroy").remove(); -} + form_closing: function(event, ui) {}, + dialog_closing: function(event, ui) {} + }); -/** - * Toggle the processing indicator, both large and small - * @param elementID Target ID, including #, to apply .gLoadingSize - */ -function showLoading(elementID) { - var size; - switch (elementID) { - case "#gDialog": - case "#gPanel": - size = "Large"; - break; - default: - size = "Small"; - break; - } - $(elementID).toggleClass("gLoading" + size); -} + $.extend($.ui.galleryDialog, { + defaults: { + autoOpen: false, + autoResize: true, + modal: true, + resizable: false, + position: "center" + } + }); +})(jQuery); diff --git a/modules/gallery/views/after_install.html.php b/modules/gallery/views/after_install.html.php index e4842163..feb2d281 100644 --- a/modules/gallery/views/after_install.html.php +++ b/modules/gallery/views/after_install.html.php @@ -16,7 +16,7 @@ title="" id="gAfterInstallChangePasswordLink" class="gButtonLink ui-state-default ui-corners-all">

                        diff --git a/modules/server_add/views/server_add_tree_dialog.html.php b/modules/server_add/views/server_add_tree_dialog.html.php index 21952849..5c5dfd0f 100644 --- a/modules/server_add/views/server_add_tree_dialog.html.php +++ b/modules/server_add/views/server_add_tree_dialog.html.php @@ -34,7 +34,7 @@ - @@ -48,6 +48,9 @@ progressbar("value", 0); $("#gProgress").slideDown("fast", function() { start_add() }); }); + $("#gServerCloseButton").click(function(event) { + $("#gDialog").dialog("close"); + }); }); diff --git a/modules/tag/js/tag.js b/modules/tag/js/tag.js index 765c2a35..535582c5 100644 --- a/modules/tag/js/tag.js +++ b/modules/tag/js/tag.js @@ -23,7 +23,7 @@ function closeEditInPlaceForms() { $("#gRenameTagForm").parent().html($("#gRenameTagForm").parent().data("revert")); li.height(""); $(".gEditable", li).bind("click", editInPlace); - $(".gDialogLink", li).bind("click", handleDialogEvent); + $(".gDialogLink", li).galleryDialog(); } } diff --git a/modules/user/views/admin_users.html.php b/modules/user/views/admin_users.html.php index 542b8b8b..a487d565 100644 --- a/modules/user/views/admin_users.html.php +++ b/modules/user/views/admin_users.html.php @@ -28,7 +28,7 @@ {}, function(data) { $("#group-" + group_id).html(data); - $("#group-" + group_id + " .gDialogLink").bind("click", handleDialogEvent); + $("#group-" + group_id + " .gDialogLink").galleryDialog()); }); } diff --git a/themes/admin_default/js/ui.init.js b/themes/admin_default/js/ui.init.js index 63b74300..eea3cab2 100644 --- a/themes/admin_default/js/ui.init.js +++ b/themes/admin_default/js/ui.init.js @@ -17,7 +17,7 @@ $(document).ready(function(){ $("#gMessage li").showMessage(); // Initialize modal dialogs - $(".gDialogLink").bind("click", handleDialogEvent); + $(".gDialogLink").galleryDialog(); // Initialize panels $(".gPanelLink").galleryPanel(); diff --git a/themes/default/js/ui.init.js b/themes/default/js/ui.init.js index ff76c79c..33d04328 100644 --- a/themes/default/js/ui.init.js +++ b/themes/default/js/ui.init.js @@ -34,7 +34,7 @@ $(document).ready(function() { // Initialize dialogs $(".gMenuLink").addClass("gDialogLink"); $("#gLoginLink").addClass("gDialogLink"); - $(".gDialogLink").bind("click", handleDialogEvent); + $(".gDialogLink").galleryDialog(); // Initialize view menu if ($("#gViewMenu").length) { -- cgit v1.2.3 From 46b9375d9050ba7f46def18b59ee80f0ffc15d3a Mon Sep 17 00:00:00 2001 From: Tim Almdal Date: Fri, 7 Aug 2009 10:33:11 -0700 Subject: Forgot this file on the gallery dialog commit --- lib/gallery.common.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/gallery.common.js b/lib/gallery.common.js index e063462e..50652532 100644 --- a/lib/gallery.common.js +++ b/lib/gallery.common.js @@ -10,7 +10,7 @@ }); }; -// Vertically align a block element's content + // Vertically align a block element's content $.fn.vAlign = function(container) { return this.each(function(i){ if (container == null) { @@ -25,7 +25,7 @@ }); }; -// Get the viewport size + // Get the viewport size $.getViewportSize = function() { return { width : function() { -- cgit v1.2.3 From 1591c3871a41b9b0ef240c227c6049de8ae066e3 Mon Sep 17 00:00:00 2001 From: Bharat Mediratta Date: Thu, 6 Aug 2009 13:32:41 +0800 Subject: Don't show the ajaxy login link in the top right corner if we're on the login page itself. Signed-off-by: Bharat Mediratta --- modules/user/helpers/user_theme.php | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/modules/user/helpers/user_theme.php b/modules/user/helpers/user_theme.php index 69042aed..8de2d248 100644 --- a/modules/user/helpers/user_theme.php +++ b/modules/user/helpers/user_theme.php @@ -19,8 +19,10 @@ */ class user_theme_Core { static function header_top($theme) { - $view = new View("login.html"); - $view->user = user::active(); - return $view->render(); + if ($theme->page_type != "login") { + $view = new View("login.html"); + $view->user = user::active(); + return $view->render(); + } } } -- cgit v1.2.3 From 49d46e4010e428b9df97a6e7c5e55708d1c674a8 Mon Sep 17 00:00:00 2001 From: Tim Almdal Date: Fri, 7 Aug 2009 10:47:56 -0700 Subject: Change galleryPanel and galleryDialog widgets to gallery_panel and gallery_dialog respectively --- lib/gallery.dialog.js | 8 ++++---- lib/gallery.panel.js | 2 +- modules/gallery/views/after_install.html.php | 2 +- modules/tag/js/tag.js | 2 +- modules/user/views/admin_users.html.php | 2 +- themes/admin_default/js/ui.init.js | 4 ++-- themes/default/js/ui.init.js | 2 +- 7 files changed, 11 insertions(+), 11 deletions(-) diff --git a/lib/gallery.dialog.js b/lib/gallery.dialog.js index 7e0ba1b4..04ab44de 100644 --- a/lib/gallery.dialog.js +++ b/lib/gallery.dialog.js @@ -1,5 +1,5 @@ (function($) { - $.widget("ui.galleryDialog", { + $.widget("ui.gallery_dialog", { _init: function() { var self = this; this.element.click(function(event){ @@ -12,7 +12,7 @@ $("body").append(eDialog); if (!self.options.close) { - self.options.close = self.closeDialog; + self.options.close = self.close_dialog; } $("#gDialog").dialog(self.options); @@ -91,7 +91,7 @@ ); }, - closeDialog: function (event, ui) { + close_dialog: function (event, ui) { var self = $("#gDialog").dialog("option", "self"); self.destroy(); }, @@ -124,7 +124,7 @@ dialog_closing: function(event, ui) {} }); - $.extend($.ui.galleryDialog, { + $.extend($.ui.gallery_dialog, { defaults: { autoOpen: false, autoResize: true, diff --git a/lib/gallery.panel.js b/lib/gallery.panel.js index 98d78d2a..e0bf4259 100644 --- a/lib/gallery.panel.js +++ b/lib/gallery.panel.js @@ -1,5 +1,5 @@ (function($) { - $.widget("ui.galleryPanel", { + $.widget("ui.gallery_panel", { _init: function() { var self = this; this.element.click(function(event) { diff --git a/modules/gallery/views/after_install.html.php b/modules/gallery/views/after_install.html.php index feb2d281..bfce46f0 100644 --- a/modules/gallery/views/after_install.html.php +++ b/modules/gallery/views/after_install.html.php @@ -16,7 +16,7 @@ title="" id="gAfterInstallChangePasswordLink" class="gButtonLink ui-state-default ui-corners-all">

                        diff --git a/modules/tag/js/tag.js b/modules/tag/js/tag.js index 535582c5..61ac73f4 100644 --- a/modules/tag/js/tag.js +++ b/modules/tag/js/tag.js @@ -23,7 +23,7 @@ function closeEditInPlaceForms() { $("#gRenameTagForm").parent().html($("#gRenameTagForm").parent().data("revert")); li.height(""); $(".gEditable", li).bind("click", editInPlace); - $(".gDialogLink", li).galleryDialog(); + $(".gDialogLink", li).gallery_dialog(); } } diff --git a/modules/user/views/admin_users.html.php b/modules/user/views/admin_users.html.php index a487d565..9bd4c068 100644 --- a/modules/user/views/admin_users.html.php +++ b/modules/user/views/admin_users.html.php @@ -28,7 +28,7 @@ {}, function(data) { $("#group-" + group_id).html(data); - $("#group-" + group_id + " .gDialogLink").galleryDialog()); + $("#group-" + group_id + " .gDialogLink").gallery_dialog(); }); } diff --git a/themes/admin_default/js/ui.init.js b/themes/admin_default/js/ui.init.js index eea3cab2..89dd5b47 100644 --- a/themes/admin_default/js/ui.init.js +++ b/themes/admin_default/js/ui.init.js @@ -17,10 +17,10 @@ $(document).ready(function(){ $("#gMessage li").showMessage(); // Initialize modal dialogs - $(".gDialogLink").galleryDialog(); + $(".gDialogLink").gallery_dialog(); // Initialize panels - $(".gPanelLink").galleryPanel(); + $(".gPanelLink").gallery_panel(); if ($("#gPhotoStream").length) { // Vertically align thumbs in photostream diff --git a/themes/default/js/ui.init.js b/themes/default/js/ui.init.js index 33d04328..4b876c66 100644 --- a/themes/default/js/ui.init.js +++ b/themes/default/js/ui.init.js @@ -34,7 +34,7 @@ $(document).ready(function() { // Initialize dialogs $(".gMenuLink").addClass("gDialogLink"); $("#gLoginLink").addClass("gDialogLink"); - $(".gDialogLink").galleryDialog(); + $(".gDialogLink").gallery_dialog(); // Initialize view menu if ($("#gViewMenu").length) { -- cgit v1.2.3 From a302a9c3fa7ec8d11373dc5eeb9c94400a255b1a Mon Sep 17 00:00:00 2001 From: Tim Almdal Date: Fri, 7 Aug 2009 23:58:57 +0800 Subject: Refactor the gallery dialog into a jQuery widget Signed-off-by: Bharat Mediratta --- lib/gallery.common.js | 27 ++- lib/gallery.dialog.js | 252 ++++++++++----------- modules/gallery/views/after_install.html.php | 2 +- .../views/server_add_tree_dialog.html.php | 5 +- modules/tag/js/tag.js | 2 +- modules/user/views/admin_users.html.php | 2 +- themes/admin_default/js/ui.init.js | 2 +- themes/default/js/ui.init.js | 2 +- 8 files changed, 155 insertions(+), 139 deletions(-) diff --git a/lib/gallery.common.js b/lib/gallery.common.js index 1eaa6db2..e063462e 100644 --- a/lib/gallery.common.js +++ b/lib/gallery.common.js @@ -2,17 +2,15 @@ * To change this template, choose Tools | Templates * and open the template in the editor. */ -(function () { +(function ($) { $.fn.showMessage = function(message) { return this.each(function(i){ $(this).effect("highlight", {"color": "white"}, 3000); $(this).animate({opacity: 1.0}, 6000); }); }; -})(jQuery); // Vertically align a block element's content -(function () { $.fn.vAlign = function(container) { return this.each(function(i){ if (container == null) { @@ -26,10 +24,8 @@ $(el).css('margin-top', nh); }); }; -})(jQuery); // Get the viewport size -(function () { $.getViewportSize = function() { return { width : function() { @@ -40,4 +36,25 @@ } }; }; + + /** + * Toggle the processing indicator, both large and small + * @param elementID Target ID, including #, to apply .gLoadingSize + */ + $.fn.showLoading = function() { + return this.each(function(i){ + var size; + switch ($(this).attr("id")) { + case "#gDialog": + case "#gPanel": + size = "Large"; + break; + default: + size = "Small"; + break; + } + $(this).toggleClass("gLoading" + size); + }); + }; + })(jQuery); diff --git a/lib/gallery.dialog.js b/lib/gallery.dialog.js index 74c2f20e..7e0ba1b4 100644 --- a/lib/gallery.dialog.js +++ b/lib/gallery.dialog.js @@ -1,140 +1,136 @@ -/** - * Fire openDialog() and prevent links from opening - * @see openDialog() - */ -function handleDialogEvent(event) { - var target = event.currentTarget; - if (!target) { - target = event.srcElement; - } - openDialog(target); - event.preventDefault(); -} +(function($) { + $.widget("ui.galleryDialog", { + _init: function() { + var self = this; + this.element.click(function(event){ + event.preventDefault(); + var element = event.currentTarget; + var sHref = $(element).attr("href"); + var sTitle = $(element).attr("title"); + var eDialog = '
                        '; -function ajaxify_dialog() { - $("#gDialog form").ajaxForm({ - dataType: "json", - success: function(data) { - if (data.form) { - $("#gDialog form").replaceWith(data.form); - ajaxify_dialog(); - on_form_loaded(); - if (typeof data.reset == 'function') { - eval(data.reset + '()'); - } - } - if (data.result == "success") { - if (data.location) { - window.location = data.location; - } else { - window.location.reload(); - } - } - } - }); -}; + $("body").append(eDialog); + + if (!self.options.close) { + self.options.close = self.closeDialog; + } + $("#gDialog").dialog(self.options); -/** - * Display modal dialogs, populate dialog with trigger link's href - * @requires ui.core - * @requires ui.draggable - * @requires ui.resizable - * @requires ui.dialog - * @see handleDialogEvent() - * @see showLoading() - */ -function openDialog(element) { - var sHref = $(element).attr("href"); - var sTitle = $(element).attr("title"); - var eDialog = '
                        '; - var dialogWidth; + $("#gDialog").showLoading(); - $("body").append(eDialog); + $.get(sHref, function(data) { + $("#gDialog").html(data).showLoading(); - $("#gDialog").dialog({ - autoOpen: false, - autoResize: true, - modal: true, - resizable: false, - close: closeDialog - }); + if ($("#gDialog form").length) { + self._trigger("form_loaded", null, $("#gDialog form")); + } + self._layout(); - showLoading("#gDialog"); + $("#gDialog").dialog("open"); + // Remove titlebar for progress dialogs or set title + if ($("#gDialog #gProgress").length) { + $(".ui-dialog-titlebar").remove(); + } else if ($("#gDialog h1").length) { + $("#gDialog").dialog('option', 'title', $("#gDialog h1:eq(0)").html()); + } else if ($("#gDialog fieldset legend").length) { + $("#gDialog").dialog('option', 'title', $("#gDialog fieldset legend:eq(0)").html()); + } - $.get(sHref, function(data) { - showLoading("#gDialog"); - $("#gDialog").html(data); - var dialogHeight = $("#gDialog").height(); - var cssWidth = new String($("#gDialog form").css("width")); - var childWidth = cssWidth.replace(/[^0-9]/g,""); - if ($("#gDialog iframe").length) { - dialogWidth = $(window).width() - 100; - // Set the iframe width and height - $("#gDialog iframe").width("100%"); - $("#gDialog iframe").height($(window).height() - 100); - } else if (childWidth == "" || childWidth > 300) { - dialogWidth = 500; - } - $("#gDialog").dialog('option', 'width', dialogWidth); + if ($("#gDialog form").length) { + self._ajaxify_dialog(); + } + }); + $("#gDialog").dialog("option", "self", self); + return false; + }); + }, - on_form_loaded(); + destroy: function() { + if ($("#gDialog form").length) { + this._trigger("form_closing", null, $("#gDialog form")); + } + this._trigger("dialog_closing", null, $("#gDialog")); - $("#gDialog").dialog("open"); - // Remove titlebar for progress dialogs or set title - if ($("#gDialog #gProgress").length) { - $(".ui-dialog-titlebar").remove(); - } else if ($("#gDialog h1").length) { - $("#gDialog").dialog('option', 'title', $("#gDialog h1:eq(0)").html()); - } else if ($("#gDialog fieldset legend").length) { - $("#gDialog").dialog('option', 'title', $("#gDialog fieldset legend:eq(0)").html()); - } + $("#gDialog").dialog("destroy").remove(); + }, + + _layout: function() { + var dialogWidth; + var dialogHeight = $("#gDialog").height(); + var cssWidth = new String($("#gDialog form").css("width")); + var childWidth = cssWidth.replace(/[^0-9]/g,""); + if ($("#gDialog iframe").length) { + dialogWidth = $(window).width() - 100; + // Set the iframe width and height + $("#gDialog iframe").width("100%").height($(window).height() - 100); + } else if (childWidth == "" || childWidth > 300) { + dialogWidth = 500; + } + $("#gDialog").dialog('option', 'width', dialogWidth); + }, + + form_loaded: function event(event, ui) { + // Should be defined (and localized) in the theme + MSG_CANCEL = MSG_CANCEL || 'Cancel'; + var eCancel = '' + MSG_CANCEL + ''; + if ($("#gDialog .submit").length) { + $("#gDialog .submit").addClass("ui-state-default ui-corner-all"); + $("#gDialog .submit").parent().append(eCancel); + $("#gDialog .gCancel").click(function(event) { + $("gDialog").dialog("close"); + event.preventDefault(); + }); + } + $("#gDialog .ui-state-default").hover( + function() { + $(this).addClass("ui-state-hover"); + }, + function() { + $(this).removeClass("ui-state-hover"); + } + ); + }, - ajaxify_dialog(); - }); - return false; -} + closeDialog: function (event, ui) { + var self = $("#gDialog").dialog("option", "self"); + self.destroy(); + }, -function on_form_loaded() { - // Should be defined (and localized) in the theme - MSG_CANCEL = MSG_CANCEL || 'Cancel'; - var eCancel = '' + MSG_CANCEL + ''; - if ($("#gDialog .submit").length) { - $("#gDialog .submit").addClass("ui-state-default ui-corner-all"); - $("#gDialog .submit").parent().append(eCancel); - } - $("#gDialog").dialog("option", "form", $("#gDialog form")); - $("#gDialog .ui-state-default").hover( - function() { - $(this).addClass("ui-state-hover"); - }, - function() { - $(this).removeClass("ui-state-hover"); - } - ); -} + _ajaxify_dialog: function() { + var self = this; + $("#gDialog form").ajaxForm({ + dataType: "json", + success: function(data) { + if (data.form) { + $("#gDialog form").replaceWith(data.form); + self._ajaxify_dialog(); + self._trigger("form_loaded", null, $("#gDialog form")); + if (typeof data.reset == 'function') { + eval(data.reset + '()'); + } + } + if (data.result == "success") { + if (data.location) { + window.location = data.location; + } else { + window.location.reload(); + } + } + } + }); + }, -function closeDialog() { - var form = $("#gDialog").dialog("option", "form"); - if (form != null) { - $("#gDialog").dialog("option", "form").trigger("form_closing"); - } - $("#gDialog").dialog("destroy").remove(); -} + form_closing: function(event, ui) {}, + dialog_closing: function(event, ui) {} + }); -/** - * Toggle the processing indicator, both large and small - * @param elementID Target ID, including #, to apply .gLoadingSize - */ -function showLoading(elementID) { - var size; - switch (elementID) { - case "#gDialog": - case "#gPanel": - size = "Large"; - break; - default: - size = "Small"; - break; - } - $(elementID).toggleClass("gLoading" + size); -} + $.extend($.ui.galleryDialog, { + defaults: { + autoOpen: false, + autoResize: true, + modal: true, + resizable: false, + position: "center" + } + }); +})(jQuery); diff --git a/modules/gallery/views/after_install.html.php b/modules/gallery/views/after_install.html.php index e4842163..feb2d281 100644 --- a/modules/gallery/views/after_install.html.php +++ b/modules/gallery/views/after_install.html.php @@ -16,7 +16,7 @@ title="" id="gAfterInstallChangePasswordLink" class="gButtonLink ui-state-default ui-corners-all">

                        diff --git a/modules/server_add/views/server_add_tree_dialog.html.php b/modules/server_add/views/server_add_tree_dialog.html.php index 21952849..5c5dfd0f 100644 --- a/modules/server_add/views/server_add_tree_dialog.html.php +++ b/modules/server_add/views/server_add_tree_dialog.html.php @@ -34,7 +34,7 @@ - @@ -48,6 +48,9 @@ progressbar("value", 0); $("#gProgress").slideDown("fast", function() { start_add() }); }); + $("#gServerCloseButton").click(function(event) { + $("#gDialog").dialog("close"); + }); }); diff --git a/modules/tag/js/tag.js b/modules/tag/js/tag.js index 765c2a35..535582c5 100644 --- a/modules/tag/js/tag.js +++ b/modules/tag/js/tag.js @@ -23,7 +23,7 @@ function closeEditInPlaceForms() { $("#gRenameTagForm").parent().html($("#gRenameTagForm").parent().data("revert")); li.height(""); $(".gEditable", li).bind("click", editInPlace); - $(".gDialogLink", li).bind("click", handleDialogEvent); + $(".gDialogLink", li).galleryDialog(); } } diff --git a/modules/user/views/admin_users.html.php b/modules/user/views/admin_users.html.php index 542b8b8b..a487d565 100644 --- a/modules/user/views/admin_users.html.php +++ b/modules/user/views/admin_users.html.php @@ -28,7 +28,7 @@ {}, function(data) { $("#group-" + group_id).html(data); - $("#group-" + group_id + " .gDialogLink").bind("click", handleDialogEvent); + $("#group-" + group_id + " .gDialogLink").galleryDialog()); }); } diff --git a/themes/admin_default/js/ui.init.js b/themes/admin_default/js/ui.init.js index 63b74300..eea3cab2 100644 --- a/themes/admin_default/js/ui.init.js +++ b/themes/admin_default/js/ui.init.js @@ -17,7 +17,7 @@ $(document).ready(function(){ $("#gMessage li").showMessage(); // Initialize modal dialogs - $(".gDialogLink").bind("click", handleDialogEvent); + $(".gDialogLink").galleryDialog(); // Initialize panels $(".gPanelLink").galleryPanel(); diff --git a/themes/default/js/ui.init.js b/themes/default/js/ui.init.js index ff76c79c..33d04328 100644 --- a/themes/default/js/ui.init.js +++ b/themes/default/js/ui.init.js @@ -34,7 +34,7 @@ $(document).ready(function() { // Initialize dialogs $(".gMenuLink").addClass("gDialogLink"); $("#gLoginLink").addClass("gDialogLink"); - $(".gDialogLink").bind("click", handleDialogEvent); + $(".gDialogLink").galleryDialog(); // Initialize view menu if ($("#gViewMenu").length) { -- cgit v1.2.3 From 30b77b5714c66f1f73fb98b61f1b17e2c84ece53 Mon Sep 17 00:00:00 2001 From: Tim Almdal Date: Sat, 8 Aug 2009 01:33:11 +0800 Subject: Forgot this file on the gallery dialog commit Signed-off-by: Bharat Mediratta --- lib/gallery.common.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/gallery.common.js b/lib/gallery.common.js index e063462e..50652532 100644 --- a/lib/gallery.common.js +++ b/lib/gallery.common.js @@ -10,7 +10,7 @@ }); }; -// Vertically align a block element's content + // Vertically align a block element's content $.fn.vAlign = function(container) { return this.each(function(i){ if (container == null) { @@ -25,7 +25,7 @@ }); }; -// Get the viewport size + // Get the viewport size $.getViewportSize = function() { return { width : function() { -- cgit v1.2.3 From 445a8fb1b6b6f410d1ea432da6d704bf2f59a14d Mon Sep 17 00:00:00 2001 From: Tim Almdal Date: Sat, 8 Aug 2009 01:47:56 +0800 Subject: Change galleryPanel and galleryDialog widgets to gallery_panel and gallery_dialog respectively Signed-off-by: Bharat Mediratta --- lib/gallery.dialog.js | 8 ++++---- lib/gallery.panel.js | 2 +- modules/gallery/views/after_install.html.php | 2 +- modules/tag/js/tag.js | 2 +- modules/user/views/admin_users.html.php | 2 +- themes/admin_default/js/ui.init.js | 4 ++-- themes/default/js/ui.init.js | 2 +- 7 files changed, 11 insertions(+), 11 deletions(-) diff --git a/lib/gallery.dialog.js b/lib/gallery.dialog.js index 7e0ba1b4..04ab44de 100644 --- a/lib/gallery.dialog.js +++ b/lib/gallery.dialog.js @@ -1,5 +1,5 @@ (function($) { - $.widget("ui.galleryDialog", { + $.widget("ui.gallery_dialog", { _init: function() { var self = this; this.element.click(function(event){ @@ -12,7 +12,7 @@ $("body").append(eDialog); if (!self.options.close) { - self.options.close = self.closeDialog; + self.options.close = self.close_dialog; } $("#gDialog").dialog(self.options); @@ -91,7 +91,7 @@ ); }, - closeDialog: function (event, ui) { + close_dialog: function (event, ui) { var self = $("#gDialog").dialog("option", "self"); self.destroy(); }, @@ -124,7 +124,7 @@ dialog_closing: function(event, ui) {} }); - $.extend($.ui.galleryDialog, { + $.extend($.ui.gallery_dialog, { defaults: { autoOpen: false, autoResize: true, diff --git a/lib/gallery.panel.js b/lib/gallery.panel.js index 98d78d2a..e0bf4259 100644 --- a/lib/gallery.panel.js +++ b/lib/gallery.panel.js @@ -1,5 +1,5 @@ (function($) { - $.widget("ui.galleryPanel", { + $.widget("ui.gallery_panel", { _init: function() { var self = this; this.element.click(function(event) { diff --git a/modules/gallery/views/after_install.html.php b/modules/gallery/views/after_install.html.php index feb2d281..bfce46f0 100644 --- a/modules/gallery/views/after_install.html.php +++ b/modules/gallery/views/after_install.html.php @@ -16,7 +16,7 @@ title="" id="gAfterInstallChangePasswordLink" class="gButtonLink ui-state-default ui-corners-all">

                        diff --git a/modules/tag/js/tag.js b/modules/tag/js/tag.js index 535582c5..61ac73f4 100644 --- a/modules/tag/js/tag.js +++ b/modules/tag/js/tag.js @@ -23,7 +23,7 @@ function closeEditInPlaceForms() { $("#gRenameTagForm").parent().html($("#gRenameTagForm").parent().data("revert")); li.height(""); $(".gEditable", li).bind("click", editInPlace); - $(".gDialogLink", li).galleryDialog(); + $(".gDialogLink", li).gallery_dialog(); } } diff --git a/modules/user/views/admin_users.html.php b/modules/user/views/admin_users.html.php index a487d565..9bd4c068 100644 --- a/modules/user/views/admin_users.html.php +++ b/modules/user/views/admin_users.html.php @@ -28,7 +28,7 @@ {}, function(data) { $("#group-" + group_id).html(data); - $("#group-" + group_id + " .gDialogLink").galleryDialog()); + $("#group-" + group_id + " .gDialogLink").gallery_dialog(); }); } diff --git a/themes/admin_default/js/ui.init.js b/themes/admin_default/js/ui.init.js index eea3cab2..89dd5b47 100644 --- a/themes/admin_default/js/ui.init.js +++ b/themes/admin_default/js/ui.init.js @@ -17,10 +17,10 @@ $(document).ready(function(){ $("#gMessage li").showMessage(); // Initialize modal dialogs - $(".gDialogLink").galleryDialog(); + $(".gDialogLink").gallery_dialog(); // Initialize panels - $(".gPanelLink").galleryPanel(); + $(".gPanelLink").gallery_panel(); if ($("#gPhotoStream").length) { // Vertically align thumbs in photostream diff --git a/themes/default/js/ui.init.js b/themes/default/js/ui.init.js index 33d04328..4b876c66 100644 --- a/themes/default/js/ui.init.js +++ b/themes/default/js/ui.init.js @@ -34,7 +34,7 @@ $(document).ready(function() { // Initialize dialogs $(".gMenuLink").addClass("gDialogLink"); $("#gLoginLink").addClass("gDialogLink"); - $(".gDialogLink").galleryDialog(); + $(".gDialogLink").gallery_dialog(); // Initialize view menu if ($("#gViewMenu").length) { -- cgit v1.2.3 From a5137f59722bcb4867ed4c863b34ddb71d7df3d9 Mon Sep 17 00:00:00 2001 From: Bharat Mediratta Date: Fri, 7 Aug 2009 11:17:07 -0700 Subject: Remove boilerplate comment. --- lib/gallery.common.js | 4 ---- 1 file changed, 4 deletions(-) diff --git a/lib/gallery.common.js b/lib/gallery.common.js index 50652532..7fced304 100644 --- a/lib/gallery.common.js +++ b/lib/gallery.common.js @@ -1,7 +1,3 @@ -/** - * To change this template, choose Tools | Templates - * and open the template in the editor. - */ (function ($) { $.fn.showMessage = function(message) { return this.each(function(i){ -- cgit v1.2.3 From e4eec71efa5f7b1902155a34f8655cebe523c358 Mon Sep 17 00:00:00 2001 From: Bharat Mediratta Date: Fri, 7 Aug 2009 11:53:40 -0700 Subject: Rename gallery.common.js functions to conform to our naming standards and have some basic namespacing: showMessage --> gallery_show_message vAlign --> gallery_valign showLoading --> gallery_show_loading Convert gallery.show_full_size.js to be a jQuery function and give it a namespace: show_full_size --> gallery_show_full_size --- lib/gallery.common.js | 9 +-- lib/gallery.dialog.js | 4 +- lib/gallery.show_full_size.js | 140 ++++++++++++++++++----------------- modules/organize/js/organize.js | 2 +- modules/organize/js/organize_init.js | 2 +- themes/admin_default/js/ui.init.js | 4 +- themes/default/js/ui.init.js | 6 +- themes/default/views/photo.html.php | 2 +- 8 files changed, 85 insertions(+), 84 deletions(-) diff --git a/lib/gallery.common.js b/lib/gallery.common.js index 7fced304..7e6acad9 100644 --- a/lib/gallery.common.js +++ b/lib/gallery.common.js @@ -1,5 +1,5 @@ (function ($) { - $.fn.showMessage = function(message) { + $.fn.gallery_show_message = function(message) { return this.each(function(i){ $(this).effect("highlight", {"color": "white"}, 3000); $(this).animate({opacity: 1.0}, 6000); @@ -7,7 +7,7 @@ }; // Vertically align a block element's content - $.fn.vAlign = function(container) { + $.fn.gallery_valign = function(container) { return this.each(function(i){ if (container == null) { container = 'div'; @@ -22,7 +22,7 @@ }; // Get the viewport size - $.getViewportSize = function() { + $.gallery_get_viewport_size = function() { return { width : function() { return $(window).width(); @@ -37,7 +37,7 @@ * Toggle the processing indicator, both large and small * @param elementID Target ID, including #, to apply .gLoadingSize */ - $.fn.showLoading = function() { + $.fn.gallery_show_loading = function() { return this.each(function(i){ var size; switch ($(this).attr("id")) { @@ -52,5 +52,4 @@ $(this).toggleClass("gLoading" + size); }); }; - })(jQuery); diff --git a/lib/gallery.dialog.js b/lib/gallery.dialog.js index 04ab44de..51ebb21a 100644 --- a/lib/gallery.dialog.js +++ b/lib/gallery.dialog.js @@ -16,10 +16,10 @@ } $("#gDialog").dialog(self.options); - $("#gDialog").showLoading(); + $("#gDialog").gallery_show_loading(); $.get(sHref, function(data) { - $("#gDialog").html(data).showLoading(); + $("#gDialog").html(data).gallery_show_loading(); if ($("#gDialog form").length) { self._trigger("form_loaded", null, $("#gDialog form")); diff --git a/lib/gallery.show_full_size.js b/lib/gallery.show_full_size.js index 8b271db9..c32195f6 100644 --- a/lib/gallery.show_full_size.js +++ b/lib/gallery.show_full_size.js @@ -1,76 +1,78 @@ -/** - * @todo Move inline CSS out to external style sheet (theme style sheet) - */ -var show_full_size = function(image_url, image_width, image_height) { - /* - * Calculate the size of the image panel based on the size of the image and the size of the - * window. Scale the image so the entire panel fits in the view port. - */ - function _auto_fit(imageWidth, imageHeight) { - // ui-dialog gives a padding of 2 pixels - var windowWidth = $(window).width() - 10; - var windowHeight = $(window).height() - 10; +(function($) { + /** + * @todo Move inline CSS out to external style sheet (theme style sheet) + */ + $.gallery_show_full_size = function(image_url, image_width, image_height) { + /* + * Calculate the size of the image panel based on the size of the image and the size of the + * window. Scale the image so the entire panel fits in the view port. + */ + function _auto_fit(imageWidth, imageHeight) { + // ui-dialog gives a padding of 2 pixels + var windowWidth = $(window).width() - 10; + var windowHeight = $(window).height() - 10; - /* If the width is greater then scale the image width first */ - if (imageWidth > windowWidth) { - var ratio = windowWidth / imageWidth; - imageWidth *= ratio; - imageHeight *= ratio; - } - /* after scaling the width, check that the height fits */ - if (imageHeight > windowHeight) { - var ratio = windowHeight / imageHeight; - imageWidth *= ratio; - imageHeight *= ratio; - } + /* If the width is greater then scale the image width first */ + if (imageWidth > windowWidth) { + var ratio = windowWidth / imageWidth; + imageWidth *= ratio; + imageHeight *= ratio; + } + /* after scaling the width, check that the height fits */ + if (imageHeight > windowHeight) { + var ratio = windowHeight / imageHeight; + imageWidth *= ratio; + imageHeight *= ratio; + } - // handle the case where the calculation is almost zero (2.14e-14) - return { - top: Number((windowHeight - imageHeight) / 2), - left: Number((windowWidth - imageWidth) / 2), - width: Number(imageWidth), - height: Number(imageHeight) - }; - } + // handle the case where the calculation is almost zero (2.14e-14) + return { + top: Number((windowHeight - imageHeight) / 2), + left: Number((windowWidth - imageWidth) / 2), + width: Number(imageWidth), + height: Number(imageHeight) + }; + } - var width = $(document).width(); - var height = $(document).height(); + var width = $(document).width(); + var height = $(document).height(); - $("body").append('
                        '); + $("body").append('
                        '); - var image_size = _auto_fit(image_width, image_height); + var image_size = _auto_fit(image_width, image_height); - $("body").append('
                        ' + - '
                        '); + $("body").append('
                        ' + + '
                        '); - $("#gFullsize").append(''); - $("#gFullsizeClose").click(function() { - $("#gFullsizeOverlay*").remove(); - $("#gFullsize").remove(); - }); - $(window).resize(function() { - $("#gFullsizeOverlay").width($(document).width()); - $("#gFullsizeOverlay").height($(document).height()); - image_size = _auto_fit(image_width, image_height); - $("#gFullsize").height(image_size.height); - $("#gFullsize").width(image_size.width); - $("#gFullsize").css("top", image_size.top); - $("#gFullsize").css("left", image_size.left); - $("#gFullSizeImage").height(image_size.height); - $("#gFullSizeImage").width(image_size.width); - }); -}; + $("#gFullsize").append(''); + $("#gFullsizeClose").click(function() { + $("#gFullsizeOverlay*").remove(); + $("#gFullsize").remove(); + }); + $(window).resize(function() { + $("#gFullsizeOverlay").width($(document).width()) + .height($(document).height()); + image_size = _auto_fit(image_width, image_height); + $("#gFullsize").height(image_size.height) + .width(image_size.width) + .css("top", image_size.top) + .css("left", image_size.left); + $("#gFullSizeImage").height(image_size.height) + .width(image_size.width); + }); + }; +})(jQuery); diff --git a/modules/organize/js/organize.js b/modules/organize/js/organize.js index f10cbcc9..31657d3a 100644 --- a/modules/organize/js/organize.js +++ b/modules/organize/js/organize.js @@ -391,7 +391,7 @@ function organize_dialog_init() { $(".gBranchText").droppable(treeDroppable); $(".gBranchText").click(organizeOpenFolder); retrieveMicroThumbs(item_id); - //showLoading("#gDialog"); + //$.gallery_show_loading("#gDialog"); $("#gMicroThumbPanel").droppable(thumbDroppable); $("#gMicroThumbPanel").selectable(selectable); diff --git a/modules/organize/js/organize_init.js b/modules/organize/js/organize_init.js index ed036fdb..30bc78dd 100644 --- a/modules/organize/js/organize_init.js +++ b/modules/organize/js/organize_init.js @@ -17,7 +17,7 @@ $("document").ready(function() { zIndex: 75 }); - //showLoading("#gDialog"); + //$.gallery_show_loading("#gDialog"); $.get(href, function(data) { $("#gDialog").html(data); diff --git a/themes/admin_default/js/ui.init.js b/themes/admin_default/js/ui.init.js index 89dd5b47..e52f0c4c 100644 --- a/themes/admin_default/js/ui.init.js +++ b/themes/admin_default/js/ui.init.js @@ -14,7 +14,7 @@ $(document).ready(function(){ $("#gSiteAdminMenu").css("display", "block"); // Initialize status message effects - $("#gMessage li").showMessage(); + $("#gMessage li").gallery_show_message(); // Initialize modal dialogs $(".gDialogLink").gallery_dialog(); @@ -24,7 +24,7 @@ $(document).ready(function(){ if ($("#gPhotoStream").length) { // Vertically align thumbs in photostream - $(".gItem").vAlign(); + $(".gItem").gallery_valign(); } // Apply jQuery UI button css to submit inputs diff --git a/themes/default/js/ui.init.js b/themes/default/js/ui.init.js index 4b876c66..b8ad68db 100644 --- a/themes/default/js/ui.init.js +++ b/themes/default/js/ui.init.js @@ -29,7 +29,7 @@ $(document).ready(function() { $("#gSiteMenu").css("display", "block"); // Initialize status message effects - $("#gMessage li").showMessage(); + $("#gMessage li").gallery_show_message(); // Initialize dialogs $(".gMenuLink").addClass("gDialogLink"); @@ -53,9 +53,9 @@ $(document).ready(function() { // Album view only if ($("#gAlbumGrid").length) { // Vertical align thumbnails/metadata in album grid - $(".gItem").vAlign(); + $(".gItem").gallery_valign(); $(".gQuick").ajaxStop(function(){ - $(".gItem").vAlign(); + $(".gItem").gallery_valign(); }); } diff --git a/themes/default/views/photo.html.php b/themes/default/views/photo.html.php index bf4d9da3..48472170 100644 --- a/themes/default/views/photo.html.php +++ b/themes/default/views/photo.html.php @@ -5,7 +5,7 @@ -- cgit v1.2.3 From 685b1ddf88c8dd7c055c1fb2571060ad1e4f4530 Mon Sep 17 00:00:00 2001 From: Tim Almdal Date: Fri, 7 Aug 2009 21:40:35 -0700 Subject: Enhance how the organize dialog degrades if the browser window is not optimal --- modules/organize/css/organize.css | 2 +- modules/organize/js/organize.js | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/modules/organize/css/organize.css b/modules/organize/css/organize.css index 56ecc309..d33dac0d 100644 --- a/modules/organize/css/organize.css +++ b/modules/organize/css/organize.css @@ -7,7 +7,6 @@ #gOrganize { overflow: hidden; - height: 100%; } #gOrganize #bd { @@ -25,6 +24,7 @@ #gOrganize .yui-gf #gMessage { margin-bottom: .4em; width: 75%; + white-space: nowrap; } #gOrganizeDetail { diff --git a/modules/organize/js/organize.js b/modules/organize/js/organize.js index 853e3eef..03d81a98 100644 --- a/modules/organize/js/organize.js +++ b/modules/organize/js/organize.js @@ -8,6 +8,7 @@ $(".sf-menu li.sfHover ul").css("z-index", 70); $("#gDialog").bind("dialogopen", function(event, ui) { + $("#gOrganize").height($("#gDialog").innerHeight() - 20); $("#gMicroThumbPanel").height($("#gDialog").innerHeight() - 90); }); -- cgit v1.2.3 From 6357f3332b9bc33b10c11dc93b83ba9e72eec109 Mon Sep 17 00:00:00 2001 From: Chad Kieffer Date: Sat, 8 Aug 2009 01:14:22 -0600 Subject: Added basic context menu affects and styles. Simplified some of the action labels in the menu. --- modules/digibug/helpers/digibug_event.php | 18 ++++----- modules/gallery/helpers/gallery.php | 30 ++++++++------- themes/default/css/screen.css | 64 ++++++++++++++++++++++++++----- themes/default/js/ui.init.js | 63 +++++++++++++++++++++++------- 4 files changed, 128 insertions(+), 47 deletions(-) diff --git a/modules/digibug/helpers/digibug_event.php b/modules/digibug/helpers/digibug_event.php index efe66a0f..93bc1747 100644 --- a/modules/digibug/helpers/digibug_event.php +++ b/modules/digibug/helpers/digibug_event.php @@ -28,19 +28,19 @@ class digibug_event_Core { static function photo_menu($menu, $theme) { $item = $theme->item(); - $menu->append( - Menu::factory("link") - ->id("digibug") - ->label(t("Print with Digibug")) - ->url(url::site("digibug/print_photo/$item->id?csrf=$theme->csrf")) - ->css_id("gDigibugLink")); + $menu->get("options_menu") + ->append(Menu::factory("link") + ->id("digibug") + ->label(t("Print with Digibug")) + ->url(url::site("digibug/print_photo/$item->id?csrf=$theme->csrf")) + ->css_id("gDigibugLink")); } static function context_menu($menu, $theme, $item) { + $item = $theme->item(); if ($item->type == "photo") { - $menu - ->append( - Menu::factory("link") + $menu->get("options_menu") + ->append(Menu::factory("link") ->id("digibug") ->label(t("Print with Digibug")) ->url(url::site("digibug/print_photo/$item->id?csrf=$theme->csrf")) diff --git a/modules/gallery/helpers/gallery.php b/modules/gallery/helpers/gallery.php index 085965a2..72e7aeeb 100644 --- a/modules/gallery/helpers/gallery.php +++ b/modules/gallery/helpers/gallery.php @@ -201,28 +201,30 @@ class gallery_Core { switch ($item->type) { case "movie": $edit_title = t("Edit this movie"); - $move_title = t("Move this movie to another album"); - $cover_title = t("Choose this movie as the album cover"); $delete_title = t("Delete this movie"); break; case "album": $edit_title = t("Edit this album"); - $move_title = t("Move this album to another album"); - $cover_title = t("Choose this album as the album cover"); $delete_title = t("Delete this album"); break; default: $edit_title = t("Edit this photo"); - $move_title = t("Move this photo to another album"); - $cover_title = t("Choose this photo as the album cover"); $delete_title = t("Delete this photo"); break; } + $cover_title = t("Choose as the album cover"); + $move_title = t("Move to another album"); $csrf = access::csrf_token(); - $menu->append(Menu::factory("dialog") + + $menu->append($options_menu = Menu::factory("submenu") + ->id("options") + ->label(t("Options")) + ->css_class("ui-icon-carat-1-n")); + + $options_menu->append(Menu::factory("dialog") ->id("edit") ->label($edit_title) ->css_clasS("ui-icon-pencil") @@ -230,22 +232,22 @@ class gallery_Core { if ($item->is_photo() && graphics::can("rotate")) { - $menu + $options_menu ->append(Menu::factory("link") ->id("rotate_ccw") - ->label(t("Rotate 90 degrees counter clockwise")) + ->label(t("Rotate 90° counter clockwise")) ->css_class("ui-icon-rotate-ccw") ->url(url::site("quick/rotate/$item->id/ccw?csrf=$csrf&page_type=$page_type"))) ->append(Menu::factory("link") ->id("rotate_cw") - ->label(t("Rotate 90 degrees clockwise")) + ->label(t("Rotate 90° clockwise")) ->css_class("ui-icon-rotate-cw") ->url(url::site("quick/rotate/$item->id/cw?csrf=$csrf&page_type=$page_type"))); } // Don't move photos from the photo page; we don't yet have a good way of redirecting after move if ($page_type == "album") { - $menu + $options_menu ->append(Menu::factory("dialog") ->id("move") ->label($move_title) @@ -264,11 +266,11 @@ class gallery_Core { } else { $disabledState = " "; } - $menu + $options_menu ->append(Menu::factory("link") ->id("make_album_cover") ->label($cover_title) - ->css_class($disabledState) + ->css_class("ui-icon-star") ->url( url::site("quick/make_album_cover/$item->id?csrf=$csrf&page_type=$page_type"))) ->append(Menu::factory("dialog") @@ -280,7 +282,7 @@ class gallery_Core { } if ($item->is_album()) { - $menu + $options_menu ->append(Menu::factory("dialog") ->id("add_item") ->label(t("Add a photo")) diff --git a/themes/default/css/screen.css b/themes/default/css/screen.css index eb092b83..1cb813f3 100644 --- a/themes/default/css/screen.css +++ b/themes/default/css/screen.css @@ -453,26 +453,32 @@ form .gError, #gContent #gAlbumGrid { margin: 1em 0; + position: relative; + z-index: 1; } #gContent #gAlbumGrid .gItem { - border: 1px solid #e8e8e8; - border-right-color: #ccc; - border-bottom-color: #ccc; + background-color: #fff; + border: 1px solid #fff; float: left; font-size: .7em; - height: 240px; + height: 220px; overflow: hidden; - padding: 15px 8px 30px 8px; + padding: .6em 8px; position: relative; text-align: center; width: 213px; + z-index: 1; } #gContent #gAlbumGrid .gItem h2 { margin: 5px 0; } +.gPhoto h2, .gItem .gMetadata { + display: none; +} + #gContent #gAlbumGrid .gAlbum { background-color: #e8e8e8; } @@ -485,6 +491,35 @@ form .gError, width: 16px; } +#gContent #gAlbumGrid #gHoverItem { + background-color: #fff; + border: 1px solid #000; + display: none; + height: auto; + margin-top: -1em; + margin-left: -.4em; + padding: 0; + position: absolute; + width: auto; + z-index: 100; +} + +#gContent #gAlbumGrid #gHoverItem .gItem { + float: none; + height: 210px; + margin: 0; + padding: 0 1em 3em; +} + +#gContent #gAlbumGrid #gHoverItem .gItem div { + margin-top: 1em !important; +} + +#gHoverItem .gItem h2, +#gHoverItem .gItem .gMetadata { + display: block; +} + /* Individual photo content ~~~~~~~~~~~~~~ */ #gContent #gItem { @@ -588,25 +623,34 @@ form .gError, /* Thumb Menu ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ -#gContent .gContextMenu { +.gContextMenu { bottom: 0; + display: none; left: 0; position: absolute; width: 100%; - display: none; } -#gContent .gContextMenu li { +.gContextMenu li { border-left: none; border-right: none; border-bottom: none; } -#gContent .gContextMenu li li { +.gContextMenu li li { padding: .3em; } -#gContent .gContextMenu a:hover { + +#gHoverItem .gContextMenu { + display: block; +} + +#gHoverItem .gContextMenu li { + text-align: left; +} + +#gHoverItem .gContextMenu a:hover { text-decoration: none; } diff --git a/themes/default/js/ui.init.js b/themes/default/js/ui.init.js index 6414cbcc..b3c1d514 100644 --- a/themes/default/js/ui.init.js +++ b/themes/default/js/ui.init.js @@ -96,21 +96,56 @@ $(document).ready(function() { ); // Initialize context menus - if ($("#gContent .gContextMenu").length) { - $("#gContent .gContextMenu li").addClass("ui-state-default"); - $(".gContextMenu").parent().hover( - function() { - $(this).find(".gContextMenu").slideDown("fast"); - var dialogLinks = $(this).find(".gDialogLink"); - for (var i = 0; i < dialogLinks.length; i++) { - $(dialogLinks[i]).bind("click", handleDialogEvent); + // @todo Switch Options icon to carat-1-s when menu's open + // @todo apply hover affect to links + $(".gItem").hover( + function(){ + var pos = $(this).position(); + var itemClasses = $(this).attr("class"); + var bgColor = $(this).css("background-color"); + var cont = $(this).parent(); + var iconSpan = ""; + $("#gHoverItem .ui-icon-carat-1-n").html(iconSpan + $("#gHoverItem .ui-icon-carat-1-n").html()); + + $("#gHoverItem").remove(); + cont.append("
                        " + + $(this).html() + "
                        "); + $("#gHoverItem").css("top", pos.top); + $("#gHoverItem").css("left", pos.left); + $("#gHoverItem").css("background-color", bgColor); + $("#gHoverItem").fadeIn("fast"); + $("#gHoverItem").hover( + function(){ + // Initialize context menus + $("#gContent .gContextMenu li").addClass("ui-state-default"); + $(".gContextMenu ul").hide(); + $(".gContextMenu").hover( + function() { + $(this).find("ul").slideDown("fast"); + var optLinks = $(this).find("a"); + for (var i = 0; i < optLinks.length; i++) { + var iconClass = $(optLinks[i]).attr("class").match(/ui-icon-.[^\s]*/); + iconSpan = ""; + $(optLinks[i]).html(iconSpan + $(optLinks[i]).html()); + if ($(optLinks[i]).hasClass("gDialogLink")) { + $(optLinks[i]).bind("click", handleDialogEvent); + } + } + $("#gContent .gContextMenu li a").addClass("gButtonLink ui-icon-left"); + }, + function() { + $(this).find("ul").slideUp("slow"); + } + ); + }, + function() { + $(this).hide(); } - }, - function() { - $(this).find(".gContextMenu").slideUp("slow"); - } - ); - } + ); + }, + function(){ + } + ); }); -- cgit v1.2.3 From 00098b4d1468b09ccbd5514c6b9634e92955a078 Mon Sep 17 00:00:00 2001 From: Chad Kieffer Date: Sat, 8 Aug 2009 11:59:32 -0600 Subject: Handle icon markup and styles in content menu before applying album grid hover affect. Dialog link's in context menu are broken currently --- themes/default/js/ui.init.js | 26 +++++++++----------------- 1 file changed, 9 insertions(+), 17 deletions(-) diff --git a/themes/default/js/ui.init.js b/themes/default/js/ui.init.js index 2fc0dc75..91d90b45 100644 --- a/themes/default/js/ui.init.js +++ b/themes/default/js/ui.init.js @@ -53,8 +53,13 @@ $(document).ready(function() { if ($("#gAlbumGrid").length) { // Vertical align thumbnails/metadata in album grid $(".gItem").gallery_valign(); - $(".gQuick").ajaxStop(function(){ - $(".gItem").gallery_valign(); + // Apply styles to gContextMenu + $(".gContextMenu li").addClass("ui-state-default"); + $(".gContextMenu a").addClass("gButtonLink ui-icon-left"); + $(".gContextMenu a").prepend(""); + $(".gContextMenu a span").each(function() { + var iconClass = $(this).parent().attr("class").match(/ui-icon-.[^\s]*/).toString(); + $(this).addClass(iconClass); }); } @@ -96,7 +101,6 @@ $(document).ready(function() { ); // Initialize context menus - // @todo Switch Options icon to carat-1-s when menu's open // @todo apply hover affect to links $(".gItem").hover( function(){ @@ -104,9 +108,6 @@ $(document).ready(function() { var itemClasses = $(this).attr("class"); var bgColor = $(this).css("background-color"); var cont = $(this).parent(); - var iconSpan = ""; - $("#gHoverItem .ui-icon-carat-1-n").html(iconSpan + $("#gHoverItem .ui-icon-carat-1-n").html()); - $("#gHoverItem").remove(); cont.append("
                        " + $(this).html() + "
                        "); @@ -117,21 +118,12 @@ $(document).ready(function() { $("#gHoverItem").hover( function(){ // Initialize context menus - $("#gContent .gContextMenu li").addClass("ui-state-default"); $(".gContextMenu ul").hide(); $(".gContextMenu").hover( function() { $(this).find("ul").slideDown("fast"); - var optLinks = $(this).find("a"); - for (var i = 0; i < optLinks.length; i++) { - var iconClass = $(optLinks[i]).attr("class").match(/ui-icon-.[^\s]*/); - iconSpan = ""; - $(optLinks[i]).html(iconSpan + $(optLinks[i]).html()); - if ($(optLinks[i]).hasClass("gDialogLink")) { - $(optLinks[i]).bind("click", handleDialogEvent); - } - } - $("#gContent .gContextMenu li a").addClass("gButtonLink ui-icon-left"); + var dialogLinks = $(this).find(".gDialogLink"); + $(dialgoLinks).gallery_dialog(); }, function() { $(this).find("ul").slideUp("slow"); -- cgit v1.2.3 From 3a8f1f426294737aac145d15462caa808aef14b1 Mon Sep 17 00:00:00 2001 From: Chad Kieffer Date: Sat, 8 Aug 2009 13:20:00 -0600 Subject: Cleanup context menu styles a bit --- themes/default/css/screen.css | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/themes/default/css/screen.css b/themes/default/css/screen.css index 1cb813f3..05d2977a 100644 --- a/themes/default/css/screen.css +++ b/themes/default/css/screen.css @@ -621,7 +621,7 @@ form .gError, margin-bottom: 0 !important; } -/* Thumb Menu ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ +/* Context Menu ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ .gContextMenu { bottom: 0; @@ -637,11 +637,10 @@ form .gError, border-bottom: none; } -.gContextMenu li li { - padding: .3em; +.gContextMenu li a { + line-height: 1.6em; } - #gHoverItem .gContextMenu { display: block; } -- cgit v1.2.3 From 7863aa16f9304e3c457898f22bce035bf4fedfd8 Mon Sep 17 00:00:00 2001 From: Bharat Mediratta Date: Sat, 8 Aug 2009 14:30:21 -0700 Subject: Update tags module to notify modules when items related to a tag are affected. Practically speaking this means that we'll reindex items when tags are added or removed from them. API change: Remove item_related_updated_batch event. Rationale: While this is an efficient event, it requires module developers to support two event APIs for staying up to date and increases the likelihood that they'll forget one and have data corruption. Force them all through the slower but more reliable pipe, for now. We can always try to improve efficiency by using the batch_start and batch_stop events. --- modules/comment/helpers/comment_installer.php | 13 ++++++-- modules/search/helpers/search_event.php | 5 --- modules/tag/models/tag.php | 48 +++++++++++++++++++++++++++ 3 files changed, 58 insertions(+), 8 deletions(-) diff --git a/modules/comment/helpers/comment_installer.php b/modules/comment/helpers/comment_installer.php index f54913c3..edf2427c 100644 --- a/modules/comment/helpers/comment_installer.php +++ b/modules/comment/helpers/comment_installer.php @@ -52,8 +52,8 @@ class comment_installer { } static function upgrade($version) { + $db = Database::instance(); if ($version == 1) { - $db = Database::instance(); $db->query("ALTER TABLE {comments} CHANGE `state` `state` varchar(15) default 'unpublished'"); module::set_version("comment", 2); } @@ -61,9 +61,16 @@ class comment_installer { static function uninstall() { $db = Database::instance(); - $sql = "SELECT `item_id` FROM {comments}"; - module::event("item_related_update_batch", $sql); + // Notify listeners that we're deleting some data. This is probably going to be very + // inefficient for large uninstalls, and we could make it better by doing things like passing + // a SQL fragment through so that the listeners could use subselects. But by using a single, + // simple event API we lighten the load on module developers. + foreach (ORM::factory("item") + ->join("comments", "items.id", "comments.item_id") + ->find_all() as $item) { + module::event("item_related_update", $item); + } $db->query("DROP TABLE IF EXISTS {comments};"); } } diff --git a/modules/search/helpers/search_event.php b/modules/search/helpers/search_event.php index b65763af..836bbe15 100644 --- a/modules/search/helpers/search_event.php +++ b/modules/search/helpers/search_event.php @@ -35,9 +35,4 @@ class search_event_Core { static function item_related_update($item) { search::update($item); } - - static function item_related_update_batch($sql) { - $db = Database::instance(); - $db->query("UPDATE {search_records} SET `dirty` = 1 WHERE item_id IN ($sql)"); - } } diff --git a/modules/tag/models/tag.php b/modules/tag/models/tag.php index e910a8ee..d9488e1c 100644 --- a/modules/tag/models/tag.php +++ b/modules/tag/models/tag.php @@ -54,4 +54,52 @@ class Tag_Model extends ORM { } return $model->count_all(); } + + /** + * Overload ORM::save() to trigger an item_related_update event for all items that are related + * to this tag. Since items can be added or removed as part of the save, we need to trigger an + * event for the union of all related items before and after the save. + */ + public function save() { + $db = Database::instance(); + $related_item_ids = array(); + foreach ($db->getwhere("items_tags", array("tag_id" => $this->id)) as $row) { + $related_item_ids[$row->item_id] = 1; + } + + $result = parent::save(); + + foreach ($db->getwhere("items_tags", array("tag_id" => $this->id)) as $row) { + $related_item_ids[$row->item_id] = 1; + } + + if ($related_item_ids) { + foreach (ORM::factory("item")->in("id", array_keys($related_item_ids))->find_all() as $item) { + module::event("item_related_update", $item); + } + } + + return $result; + } + + /** + * Overload ORM::delete() to trigger an item_related_update event for all items that are + * related to this tag. + */ + public function delete() { + $related_item_ids = array(); + $db = Database::Instance(); + foreach ($db->getwhere("items_tags", array("tag_id" => $this->id)) as $row) { + $related_item_ids[$row->item_id] = 1; + } + + $result = parent::delete(); + + if ($related_item_ids) { + foreach (ORM::factory("item")->in("id", array_keys($related_item_ids))->find_all() as $item) { + module::event("item_related_update", $item); + } + } + return $result; + } } \ No newline at end of file -- cgit v1.2.3 From 6641fec60da715161f0f7f11235c1720d17ec19e Mon Sep 17 00:00:00 2001 From: Bharat Mediratta Date: Sat, 8 Aug 2009 14:37:55 -0700 Subject: Use the same pager layout as we do in photo.html.php. --- themes/default/views/movie.html.php | 29 +++++++++++++++++++++-------- 1 file changed, 21 insertions(+), 8 deletions(-) diff --git a/themes/default/views/movie.html.php b/themes/default/views/movie.html.php index 66c80ded..c90a370c 100644 --- a/themes/default/views/movie.html.php +++ b/themes/default/views/movie.html.php @@ -2,16 +2,29 @@
                        photo_top() ?> -
                          -
                        • $position, "total" => $sibling_count)) ?>
                        • - -
                        • - - -
                        • - +
                            +
                          • + + + + + + + +
                          • +
                          • $position, "total" => $sibling_count)) ?>
                          • +
                          • + + + + + + + +
                          + movie_img(array("class" => "gMovie", "id" => "gMovieId-{$item->id}")) ?>
                          -- cgit v1.2.3 From cb1ae141bb65a5da42e94910214abbf5ac367920 Mon Sep 17 00:00:00 2001 From: Tim Almdal Date: Sat, 8 Aug 2009 15:46:53 -0700 Subject: Create an new option 'immediate' and if set to true then don't try to set up click events, but just show the dialog. Also remove the destroy method and put all the cleanup into the dialog close handler --- lib/gallery.dialog.js | 88 ++++++++++++++-------------- modules/gallery/js/quick.js | 2 +- modules/gallery/views/after_install.html.php | 2 +- 3 files changed, 47 insertions(+), 45 deletions(-) diff --git a/lib/gallery.dialog.js b/lib/gallery.dialog.js index 51ebb21a..9aebd455 100644 --- a/lib/gallery.dialog.js +++ b/lib/gallery.dialog.js @@ -2,56 +2,54 @@ $.widget("ui.gallery_dialog", { _init: function() { var self = this; - this.element.click(function(event){ - event.preventDefault(); - var element = event.currentTarget; - var sHref = $(element).attr("href"); - var sTitle = $(element).attr("title"); - var eDialog = '
                          '; - - $("body").append(eDialog); + var options = self.options; + if (!self.options.immediate) { + this.element.click(function(event) { + event.preventDefault(); + self._show($(event.currentTarget).attr("href")); + return false; + }); + } else { + self._show(this.element.attr("href")); + } + }, - if (!self.options.close) { - self.options.close = self.close_dialog; - } - $("#gDialog").dialog(self.options); + _show: function(sHref) { + var self = this; + var eDialog = '
                          '; - $("#gDialog").gallery_show_loading(); + $("body").append(eDialog); - $.get(sHref, function(data) { - $("#gDialog").html(data).gallery_show_loading(); + if (!self.options.close) { + self.options.close = self.close_dialog; + } + $("#gDialog").dialog(self.options); - if ($("#gDialog form").length) { - self._trigger("form_loaded", null, $("#gDialog form")); - } - self._layout(); + $("#gDialog").gallery_show_loading(); - $("#gDialog").dialog("open"); - // Remove titlebar for progress dialogs or set title - if ($("#gDialog #gProgress").length) { - $(".ui-dialog-titlebar").remove(); - } else if ($("#gDialog h1").length) { - $("#gDialog").dialog('option', 'title', $("#gDialog h1:eq(0)").html()); - } else if ($("#gDialog fieldset legend").length) { - $("#gDialog").dialog('option', 'title', $("#gDialog fieldset legend:eq(0)").html()); - } + $.get(sHref, function(data) { + $("#gDialog").html(data).gallery_show_loading(); - if ($("#gDialog form").length) { - self._ajaxify_dialog(); - } - }); - $("#gDialog").dialog("option", "self", self); - return false; - }); - }, + if ($("#gDialog form").length) { + self._trigger("form_loaded", null, $("#gDialog form")); + } + self._layout(); - destroy: function() { - if ($("#gDialog form").length) { - this._trigger("form_closing", null, $("#gDialog form")); - } - this._trigger("dialog_closing", null, $("#gDialog")); + $("#gDialog").dialog("open"); + // Remove titlebar for progress dialogs or set title + if ($("#gDialog #gProgress").length) { + $(".ui-dialog-titlebar").remove(); + } else if ($("#gDialog h1").length) { + $("#gDialog").dialog('option', 'title', $("#gDialog h1:eq(0)").html()); + } else if ($("#gDialog fieldset legend").length) { + $("#gDialog").dialog('option', 'title', $("#gDialog fieldset legend:eq(0)").html()); + } - $("#gDialog").dialog("destroy").remove(); + if ($("#gDialog form").length) { + self._ajaxify_dialog(); + } + }); + $("#gDialog").dialog("option", "self", self); }, _layout: function() { @@ -93,7 +91,11 @@ close_dialog: function (event, ui) { var self = $("#gDialog").dialog("option", "self"); - self.destroy(); + if ($("#gDialog form").length) { + self._trigger("form_closing", null, $("#gDialog form")); + } + self._trigger("dialog_closing", null, $("#gDialog")); + $("#gDialog").dialog("destroy").remove(); }, _ajaxify_dialog: function() { diff --git a/modules/gallery/js/quick.js b/modules/gallery/js/quick.js index fda6470f..dfa61c20 100644 --- a/modules/gallery/js/quick.js +++ b/modules/gallery/js/quick.js @@ -46,7 +46,7 @@ var quick_do = function(cont, pane, img) { return false; } if (pane.hasClass("gDialogLink")) { - openDialog(pane); + $(pane).gallery_dialog({immediate: 1}); } else { img.css("opacity", "0.1"); cont.addClass("gLoadingLarge"); diff --git a/modules/gallery/views/after_install.html.php b/modules/gallery/views/after_install.html.php index bfce46f0..76b59474 100644 --- a/modules/gallery/views/after_install.html.php +++ b/modules/gallery/views/after_install.html.php @@ -16,7 +16,7 @@ title="" id="gAfterInstallChangePasswordLink" class="gButtonLink ui-state-default ui-corners-all">

                          -- cgit v1.2.3 From ae428a7e21ab712718e2d4d20381c2772011ff1f Mon Sep 17 00:00:00 2001 From: Tim Almdal Date: Sat, 8 Aug 2009 15:52:04 -0700 Subject: remove a debug statement left over from previous commit --- lib/gallery.dialog.js | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/gallery.dialog.js b/lib/gallery.dialog.js index 9aebd455..4bbb8ab7 100644 --- a/lib/gallery.dialog.js +++ b/lib/gallery.dialog.js @@ -2,7 +2,6 @@ $.widget("ui.gallery_dialog", { _init: function() { var self = this; - var options = self.options; if (!self.options.immediate) { this.element.click(function(event) { event.preventDefault(); -- cgit v1.2.3 From e04675470bc43b8abd792c4c1621e5c0dc61f36a Mon Sep 17 00:00:00 2001 From: Tim Almdal Date: Sat, 8 Aug 2009 16:01:20 -0700 Subject: Forgot to save this file when i changed the value from 1 to true --- modules/gallery/views/after_install.html.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/gallery/views/after_install.html.php b/modules/gallery/views/after_install.html.php index 76b59474..41e600fb 100644 --- a/modules/gallery/views/after_install.html.php +++ b/modules/gallery/views/after_install.html.php @@ -16,7 +16,7 @@ title="" id="gAfterInstallChangePasswordLink" class="gButtonLink ui-state-default ui-corners-all">

                          -- cgit v1.2.3 From e4fb6959aff3d688db9821eadd0d24006c9c77d6 Mon Sep 17 00:00:00 2001 From: Tim Almdal Date: Sat, 8 Aug 2009 16:18:33 -0700 Subject: Forgot to save this one before committing the last two times... duh. Completes the conversion from using 1 to true for the immediate paramter to gallery_dialog --- modules/gallery/js/quick.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/gallery/js/quick.js b/modules/gallery/js/quick.js index dfa61c20..1c243b79 100644 --- a/modules/gallery/js/quick.js +++ b/modules/gallery/js/quick.js @@ -46,7 +46,7 @@ var quick_do = function(cont, pane, img) { return false; } if (pane.hasClass("gDialogLink")) { - $(pane).gallery_dialog({immediate: 1}); + $(pane).gallery_dialog({immediate: true}); } else { img.css("opacity", "0.1"); cont.addClass("gLoadingLarge"); -- cgit v1.2.3 From 1c5b04a2c5d58838dbea413359c9b114f7077ca8 Mon Sep 17 00:00:00 2001 From: Tim Almdal Date: Sat, 8 Aug 2009 16:26:34 -0700 Subject: Fix the problem where the login page and edit permission pages were supersized based on ly last commit. --- lib/gallery.dialog.js | 2 +- modules/organize/views/organize_dialog.html.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/gallery.dialog.js b/lib/gallery.dialog.js index 6c2993fd..ace588f6 100644 --- a/lib/gallery.dialog.js +++ b/lib/gallery.dialog.js @@ -61,7 +61,7 @@ dialogWidth = size.width() - 100; // Set the iframe width and height $("#gDialog iframe").width("100%").height(size.height() - 100); - } else if ($("#gDialog form").length == 0) { + } else if ($("#gDialog .gDialogPanel").length) { dialogWidth = size.width() - 100; $("#gDialog").dialog("option", "height", size.height() - 100); } else if (childWidth == "" || childWidth > 300) { diff --git a/modules/organize/views/organize_dialog.html.php b/modules/organize/views/organize_dialog.html.php index 0daa328d..b946d82b 100644 --- a/modules/organize/views/organize_dialog.html.php +++ b/modules/organize/views/organize_dialog.html.php @@ -1,6 +1,6 @@ " /> -
                          +

                          p::purify($title))) ?>

                          -- cgit v1.2.3 From 9fa4e8972596d015d4e4259aabb600c886d6381e Mon Sep 17 00:00:00 2001 From: Chad Kieffer Date: Sat, 8 Aug 2009 20:39:19 -0600 Subject: Fixed typo. Dialog links still broken. Now, wiht more speling! --- themes/default/js/ui.init.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/themes/default/js/ui.init.js b/themes/default/js/ui.init.js index 91d90b45..a8c558c5 100644 --- a/themes/default/js/ui.init.js +++ b/themes/default/js/ui.init.js @@ -123,7 +123,7 @@ $(document).ready(function() { function() { $(this).find("ul").slideDown("fast"); var dialogLinks = $(this).find(".gDialogLink"); - $(dialgoLinks).gallery_dialog(); + $(dialogLinks).gallery_dialog(); }, function() { $(this).find("ul").slideUp("slow"); -- cgit v1.2.3 From c9f5000e65f66b3342f2cc6e2e9623eac72ff223 Mon Sep 17 00:00:00 2001 From: Bharat Mediratta Date: Sat, 8 Aug 2009 20:31:16 -0700 Subject: Improve the graphics toolkit detection code so that properly identifies situations where its restricted by open_basedir. We now track more informatoin about the toolkit including the version and any errors we encountered while doing the detection so that we can provide more info downstream. This makes graphics::detect_toolkits() a little heavier, but that's ok because it should not be called very often. In the process, refactor the controller and view hierarchy so that it's a little more straightforward in the code. Fixes ticket #616. --- modules/gallery/controllers/admin_graphics.php | 39 +++------ modules/gallery/helpers/graphics.php | 92 ++++++++++++++++++++-- modules/gallery/views/admin_graphics.html.php | 14 +++- modules/gallery/views/admin_graphics_gd.html.php | 15 ++-- .../views/admin_graphics_graphicsmagick.html.php | 10 +-- .../views/admin_graphics_imagemagick.html.php | 12 +-- modules/gallery/views/admin_graphics_none.html.php | 2 +- 7 files changed, 127 insertions(+), 57 deletions(-) diff --git a/modules/gallery/controllers/admin_graphics.php b/modules/gallery/controllers/admin_graphics.php index 72f8d8e1..565ee1b0 100644 --- a/modules/gallery/controllers/admin_graphics.php +++ b/modules/gallery/controllers/admin_graphics.php @@ -21,41 +21,24 @@ class Admin_Graphics_Controller extends Admin_Controller { public function index() { $view = new Admin_View("admin.html"); $view->content = new View("admin_graphics.html"); - $view->content->available = ""; - - $tk = new ArrayObject(graphics::detect_toolkits(), ArrayObject::ARRAY_AS_PROPS); - $active = module::get_var("gallery", "graphics_toolkit", "none"); - foreach (array("gd", "imagemagick", "graphicsmagick", "none") as $id) { - if ($id == $active) { - $view->content->active = new View("admin_graphics_$id.html"); - $view->content->active->tk = $tk; - $view->content->active->is_active = true; - } else if ($id != "none") { - $v = new View("admin_graphics_$id.html"); - $v->tk = $tk; - $v->is_active = false; - $view->content->available .= $v; - } - } - + $view->content->tk = graphics::detect_toolkits(); + $view->content->active = module::get_var("gallery", "graphics_toolkit", "none"); print $view; } - public function choose($toolkit) { + public function choose($toolkit_id) { access::verify_csrf(); - if ($toolkit != module::get_var("gallery", "graphics_toolkit")) { - module::set_var("gallery", "graphics_toolkit", $toolkit); - - $toolkit_info = graphics::detect_toolkits(); - if ($toolkit == "graphicsmagick" || $toolkit == "imagemagick") { - module::set_var("gallery", "graphics_toolkit_path", $toolkit_info[$toolkit]); - } + if ($toolkit_id != module::get_var("gallery", "graphics_toolkit")) { + $tk = graphics::detect_toolkits(); + module::set_var("gallery", "graphics_toolkit", $toolkit_id); + module::set_var("gallery", "graphics_toolkit_path", dirname($tk->$toolkit_id->dir)); site_status::clear("missing_graphics_toolkit"); - message::success(t("Updated Graphics Toolkit")); - log::success("graphics", t("Changed graphics toolkit to: %toolkit", - array("toolkit" => $toolkit))); + + $msg = t("Changed graphics toolkit to: %toolkit", array("toolkit" => $tk->$toolkit_id->name)); + message::success($msg); + log::success("graphics", $msg); } url::redirect("admin/graphics"); diff --git a/modules/gallery/helpers/graphics.php b/modules/gallery/helpers/graphics.php index d506a982..7dc46eeb 100644 --- a/modules/gallery/helpers/graphics.php +++ b/modules/gallery/helpers/graphics.php @@ -339,15 +339,90 @@ class graphics_Core { * GraphicsMagick we return the path to the directory containing the appropriate binaries. */ static function detect_toolkits() { + $toolkits = new stdClass(); + + // GD is special, it doesn't use exec() $gd = function_exists("gd_info") ? gd_info() : array(); - $exec = function_exists("exec"); + $toolkits->gd->name = "GD"; if (!isset($gd["GD Version"])) { - $gd["GD Version"] = false; + $toolkits->gd->installed = false; + $toolkits->gd->error = t("GD is not installed"); + } else { + $toolkits->gd->installed = true; + $toolkits->gd->version = $gd["GD Version"]; + $toolkits->gd->rotate = function_exists("imagerotate"); + $toolkits->gd->binary = ""; + $toolkits->gd->dir = ""; + + if (!$toolkits->gd->rotate) { + $toolkits->gd->error = + t("You have GD version %version, but it lacks image rotation.", + array("version" => $gd["GD Version"])); + } + } + + if (!function_exists("exec")) { + $toolkits->imagemagick->installed = false; + $toolkits->imagemagick->error = t("ImageMagick requires the exec function"); + + $toolkits->graphicsmagick->installed = false; + $toolkits->graphicsmagick->error = t("GraphicsMagick requires the exec function"); + } else { + putenv("PATH=" . getenv("PATH") . ":/usr/local/bin:/opt/local/bin:/opt/bin"); + + // @todo: consider refactoring the two segments below into a loop since they are so + // similar. + + // ImageMagick + $path = exec("which convert"); + $toolkits->imagemagick->name = "ImageMagick"; + if ($path) { + if (@is_file($path)) { + preg_match('/Version: \S+ (\S+)/', `convert -v`, $matches); + $version = $matches[1]; + + $toolkits->imagemagick->installed = true; + $toolkits->imagemagick->version = $version; + $toolkits->imagemagick->binary = $path; + $toolkits->imagemagick->dir = dirname($path); + $toolkits->imagemagick->rotate = true; + } else { + $toolkits->imagemagick->installed = false; + $toolkits->imagemagick->error = + t("ImageMagick is installed, but PHP's open_basedir restriction " . + "prevents Gallery from using it."); + } + } else { + $toolkits->imagemagick->installed = false; + $toolkits->imagemagick->error = t("We could not locate ImageMagick on your system."); + } + + // GraphicsMagick + $path = exec("which gm"); + $toolkits->graphicsmagick->name = "GraphicsMagick"; + if ($path) { + if (@is_file($path)) { + preg_match('/\S+ (\S+)/', `gm version`, $matches); + $version = $matches[1]; + + $toolkits->graphicsmagick->installed = true; + $toolkits->graphicsmagick->version = $version; + $toolkits->graphicsmagick->binary = $path; + $toolkits->graphicsmagick->dir = dirname($path); + $toolkits->graphicsmagick->rotate = true; + } else { + $toolkits->graphicsmagick->installed = false; + $toolkits->graphicsmagick->error = + t("GraphicsMagick is installed, but PHP's open_basedir restriction " . + "prevents Gallery from using it."); + } + } else { + $toolkits->graphicsmagick->installed = false; + $toolkits->graphicsmagick->error = t("We could not locate GraphicsMagick on your system."); + } } - putenv("PATH=" . getenv("PATH") . ":/usr/local/bin:/opt/local/bin:/opt/bin"); - return array("gd" => $gd, - "imagemagick" => $exec ? dirname(exec("which convert")) : false, - "graphicsmagick" => $exec ? dirname(exec("which gm")) : false); + + return $toolkits; } /** @@ -357,12 +432,13 @@ class graphics_Core { // Detect a graphics toolkit $toolkits = graphics::detect_toolkits(); foreach (array("imagemagick", "graphicsmagick", "gd") as $tk) { - if ($toolkits[$tk]) { + if ($toolkits->$tk->installed) { module::set_var("gallery", "graphics_toolkit", $tk); - module::set_var("gallery", "graphics_toolkit_path", $tk == "gd" ? "" : $toolkits[$tk]); + module::set_var("gallery", "graphics_toolkit_path", $toolkits->$tk->dir); break; } } + if (!module::get_var("gallery", "graphics_toolkit")) { site_status::warning( t("Graphics toolkit missing! Please choose a toolkit", diff --git a/modules/gallery/views/admin_graphics.html.php b/modules/gallery/views/admin_graphics.html.php index 08374471..c4a2f5c6 100644 --- a/modules/gallery/views/admin_graphics.html.php +++ b/modules/gallery/views/admin_graphics.html.php @@ -9,8 +9,8 @@ }; $("#gAdminGraphics div.gAvailable .gBlock").click(select_toolkit); }); - +

                          @@ -18,11 +18,19 @@

                          - + + + + $tk->$active, "is_active" => true)) ?> +

                          - + + + $tk->$id, "is_active" => false)) ?> + +
                          diff --git a/modules/gallery/views/admin_graphics_gd.html.php b/modules/gallery/views/admin_graphics_gd.html.php index b77da8e3..aa9ee67c 100644 --- a/modules/gallery/views/admin_graphics_gd.html.php +++ b/modules/gallery/views/admin_graphics_gd.html.php @@ -1,23 +1,26 @@ -
                          gd["GD Version"] ? " gInstalledToolkit" : " gUnavailable" ?>"> +
                          installed ? " gInstalledToolkit" : " gUnavailable" ?>"> " alt="" />

                          GD website for more information.", array("url" => "http://www.boutell.com/gd")) ?>

                          - gd["GD Version"] && function_exists('imagerotate')): ?> + installed && $tk->rotate): ?>

                          - $tk->gd["GD Version"])) ?> + $tk->version)) ?>

                          - gd["GD Version"]): ?> + installed): ?> + + error): ?>

                          - $tk->gd["GD Version"])) ?> + error ?>

                          + +

                          diff --git a/modules/gallery/views/admin_graphics_graphicsmagick.html.php b/modules/gallery/views/admin_graphics_graphicsmagick.html.php index e2cd0777..bf3ad339 100644 --- a/modules/gallery/views/admin_graphics_graphicsmagick.html.php +++ b/modules/gallery/views/admin_graphics_graphicsmagick.html.php @@ -1,21 +1,21 @@ -
                          graphicsmagick ? " gInstalledToolkit" : " gUnavailable" ?>"> +
                          installed ? " gInstalledToolkit" : " gUnavailable" ?>">

                          " alt="" />

                          GraphicsMagick website for more information.", array("url" => "http://www.graphicsmagick.org")) ?>

                          - graphicsmagick): ?> + installed): ?>

                          - $tk->graphicsmagick)) ?> + $tk->version, "dir" => $tk->dir)) ?>

                          -

                          - +

                          + error ?>

                          diff --git a/modules/gallery/views/admin_graphics_imagemagick.html.php b/modules/gallery/views/admin_graphics_imagemagick.html.php index 081ddc15..b8f7ffb8 100644 --- a/modules/gallery/views/admin_graphics_imagemagick.html.php +++ b/modules/gallery/views/admin_graphics_imagemagick.html.php @@ -1,21 +1,21 @@ -
                          imagemagick ? " gInstalledToolkit" : " gUnavailable" ?>"> +
                          installed ? " gInstalledToolkit" : " gUnavailable" ?>">

                          " alt="" />

                          ImageMagick website for more information.", array("url" => "http://www.imagemagick.org")) ?>

                          - imagemagick): ?> + installed): ?>

                          - $tk->imagemagick)) ?> + $tk->version, "dir" => $tk->dir)) ?>

                          - -

                          - + error): ?> +

                          + error ?>

                          diff --git a/modules/gallery/views/admin_graphics_none.html.php b/modules/gallery/views/admin_graphics_none.html.php index 5306a70d..be2a580d 100644 --- a/modules/gallery/views/admin_graphics_none.html.php +++ b/modules/gallery/views/admin_graphics_none.html.php @@ -2,6 +2,6 @@

                          - +

                          -- cgit v1.2.3 From 12f25a7e55d5aab4c4170eaa3bcb761cf5514be2 Mon Sep 17 00:00:00 2001 From: Bharat Mediratta Date: Sat, 8 Aug 2009 21:26:55 -0700 Subject: Fix the after_install loader to immediately open the "Welcome to Gallery 3!" dialog, but not immediately open the "change your password" dialog. --- modules/gallery/views/after_install.html.php | 2 +- modules/gallery/views/after_install_loader.html.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/gallery/views/after_install.html.php b/modules/gallery/views/after_install.html.php index 41e600fb..bfce46f0 100644 --- a/modules/gallery/views/after_install.html.php +++ b/modules/gallery/views/after_install.html.php @@ -16,7 +16,7 @@ title="" id="gAfterInstallChangePasswordLink" class="gButtonLink ui-state-default ui-corners-all">

                          diff --git a/modules/gallery/views/after_install_loader.html.php b/modules/gallery/views/after_install_loader.html.php index baf91eed..54484963 100644 --- a/modules/gallery/views/after_install_loader.html.php +++ b/modules/gallery/views/after_install_loader.html.php @@ -3,5 +3,5 @@ title="" href=""/> -- cgit v1.2.3 From 5c25973ee8f9601353917767d31f0af49cd93737 Mon Sep 17 00:00:00 2001 From: Bharat Mediratta Date: Sun, 9 Aug 2009 00:02:13 -0700 Subject: Require a valid url for users. Fixes ticket #612. --- modules/user/models/user.php | 1 + 1 file changed, 1 insertion(+) diff --git a/modules/user/models/user.php b/modules/user/models/user.php index 4b43adff..55562f34 100644 --- a/modules/user/models/user.php +++ b/modules/user/models/user.php @@ -25,6 +25,7 @@ class User_Model extends ORM { "full_name" => "length[0,255]", "email" => "valid_email|length[1,255]", "password" => "length[1,40]", + "url" => "valid_url", "locale" => "length[2,10]"); public function __set($column, $value) { -- cgit v1.2.3 From 39d0098038b828c3cf5d63caa06f1b6d57904f32 Mon Sep 17 00:00:00 2001 From: Tim Almdal Date: Sun, 9 Aug 2009 09:00:10 -0700 Subject: Enable microthumbnail selection --- modules/organize/css/organize.css | 11 ++++++----- modules/organize/js/organize.js | 6 ++++-- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/modules/organize/css/organize.css b/modules/organize/css/organize.css index d33dac0d..a4b5fdbd 100644 --- a/modules/organize/css/organize.css +++ b/modules/organize/css/organize.css @@ -95,11 +95,6 @@ padding: .5em; } -.gMicroThumbContainer { -// padding: 0 .5em; -// opacity: .4; -} - .gMicroThumb { display: block; float: left; @@ -107,10 +102,16 @@ height: 9em; margin-bottom: 1em; margin-left: 1em; + opacity: .5; text-align: center; width: 9em; } +.gMicroThumb.ui-selected { + opacity: 1; +} + + .gThumbnail { padding: .5em; } diff --git a/modules/organize/js/organize.js b/modules/organize/js/organize.js index 03d81a98..05693200 100644 --- a/modules/organize/js/organize.js +++ b/modules/organize/js/organize.js @@ -5,8 +5,8 @@ */ init: function(data) { // Deal with ui.jquery bug: http://dev.jqueryui.com/ticket/4475 (target 1.8?) - $(".sf-menu li.sfHover ul").css("z-index", 70); - + $(".sf-menu li.sfHover ul").css("z-index", 68); + $("#gDialog").dialog("option", "zIndex", 70); $("#gDialog").bind("dialogopen", function(event, ui) { $("#gOrganize").height($("#gDialog").innerHeight() - 20); $("#gMicroThumbPanel").height($("#gDialog").innerHeight() - 90); @@ -22,6 +22,8 @@ $(".gBranchText span").click($.organize.collapse_or_expand_tree); $(".gBranchText").click($.organize.show_album); + + $("#gMicroThumbGrid").selectable({filter: ".gMicroThumb"}); }, /** -- cgit v1.2.3 From 2f4c4a3f706d98be7dd41f8fa7c9124314c515c8 Mon Sep 17 00:00:00 2001 From: Chad Kieffer Date: Sun, 9 Aug 2009 11:31:31 -0600 Subject: Rename resizeImage gallery_fit_image to follow convention. Move the function to gallery.common.js. --- lib/gallery.common.js | 21 ++++++++++++++++++++- themes/default/js/ui.init.js | 24 ++++-------------------- 2 files changed, 24 insertions(+), 21 deletions(-) diff --git a/lib/gallery.common.js b/lib/gallery.common.js index 7e6acad9..08656a83 100644 --- a/lib/gallery.common.js +++ b/lib/gallery.common.js @@ -12,7 +12,7 @@ if (container == null) { container = 'div'; } - $(this).html("<" + container + ">" + $(this).html() + ""); + $(this).html("<" + container + " class=\"gValign\">" + $(this).html() + ""); var el = $(this).children(container + ":first"); var elh = $(el).height(); var ph = $(this).height(); @@ -52,4 +52,23 @@ $(this).toggleClass("gLoading" + size); }); }; + + /** + * Reduce the width of an image if it's wider than its parent container + * @param elementID The image's container + */ + $.fn.gallery_fit_image = function() { + var photo = $(this).find("img").filter(function() { + return this.id.match(/gPhotoId-\d+/); + }); + var cont_width = $(this).width(); + var photo_width = photo.width(); + if (cont_width < photo_width) { + var proportion = cont_width / photo_width; + photo.width(cont_width); + photo.height(proportion * photo.height()); + } + }; + })(jQuery); + diff --git a/themes/default/js/ui.init.js b/themes/default/js/ui.init.js index a8c558c5..29680a48 100644 --- a/themes/default/js/ui.init.js +++ b/themes/default/js/ui.init.js @@ -58,16 +58,15 @@ $(document).ready(function() { $(".gContextMenu a").addClass("gButtonLink ui-icon-left"); $(".gContextMenu a").prepend(""); $(".gContextMenu a span").each(function() { - var iconClass = $(this).parent().attr("class").match(/ui-icon-.[^\s]*/).toString(); + var iconClass = $(this).parent().attr("class").match(/ui-icon-.[^\s]+/).toString(); $(this).addClass(iconClass); }); } - // Photo/Item item view only + // Photo/Item item view if ($("#gItem").length) { - // Ensure that sized image versions - // fit inside their container - sizedImage(); + // Ensure the resized image fits within its container + $("#gItem").gallery_fit_image(); // Collapse comments form, insert button to expand if ($("#gAddCommentForm").length) { @@ -140,18 +139,3 @@ $(document).ready(function() { ); }); - -/** - * Reduce width of sized photo if it's wider than its parent container - */ -function sizedImage() { - var containerWidth = $("#gItem").width(); - var oPhoto = $("#gItem img").filter(function() { - return this.id.match(/gPhotoId-/); - }); - if (containerWidth < oPhoto.width()) { - var proportion = containerWidth / oPhoto.width(); - oPhoto.width(containerWidth); - oPhoto.height(proportion * oPhoto.height()); - } -} -- cgit v1.2.3 From de00a4ac394de6ce2df4bd6e52ae52f17701f702 Mon Sep 17 00:00:00 2001 From: Chad Kieffer Date: Sun, 9 Aug 2009 11:40:39 -0600 Subject: Explicitly use gValign class rather than first child. --- lib/gallery.common.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/gallery.common.js b/lib/gallery.common.js index 08656a83..b1160e31 100644 --- a/lib/gallery.common.js +++ b/lib/gallery.common.js @@ -13,7 +13,7 @@ container = 'div'; } $(this).html("<" + container + " class=\"gValign\">" + $(this).html() + ""); - var el = $(this).children(container + ":first"); + var el = $(this).children(container + ".gValign"); var elh = $(el).height(); var ph = $(this).height(); var nh = (ph - elh) / 2; -- cgit v1.2.3 From 1231e095c824ed9961b1156d89f6a1cae231f96f Mon Sep 17 00:00:00 2001 From: Chad Kieffer Date: Sun, 9 Aug 2009 12:46:17 -0600 Subject: Keep image placement from shifting on hover, set gHoverItem height properly. --- themes/default/css/screen.css | 21 +++++++-------------- themes/default/js/ui.init.js | 38 +++++++++++++++++++++++++++++--------- 2 files changed, 36 insertions(+), 23 deletions(-) diff --git a/themes/default/css/screen.css b/themes/default/css/screen.css index 05d2977a..6a29e95f 100644 --- a/themes/default/css/screen.css +++ b/themes/default/css/screen.css @@ -475,7 +475,8 @@ form .gError, margin: 5px 0; } -.gPhoto h2, .gItem .gMetadata { +#gContent .gPhoto h2, +#gContent .gItem .gMetadata { display: none; } @@ -484,7 +485,7 @@ form .gError, } #gContent #gAlbumGrid .gAlbum h2 span { - background: transparent url('../images/ico-album.png') no-repeat top left !important; + background: transparent url('../images/ico-album.png') no-repeat top left; display: inline-block; height: 16px; margin-right: 5px; @@ -496,8 +497,6 @@ form .gError, border: 1px solid #000; display: none; height: auto; - margin-top: -1em; - margin-left: -.4em; padding: 0; position: absolute; width: auto; @@ -505,18 +504,11 @@ form .gError, } #gContent #gAlbumGrid #gHoverItem .gItem { - float: none; - height: 210px; - margin: 0; - padding: 0 1em 3em; -} - -#gContent #gAlbumGrid #gHoverItem .gItem div { - margin-top: 1em !important; + border: none; } -#gHoverItem .gItem h2, -#gHoverItem .gItem .gMetadata { +#gContent #gHoverItem .gItem h2, +#gContent #gHoverItem .gItem .gMetadata { display: block; } @@ -627,6 +619,7 @@ form .gError, bottom: 0; display: none; left: 0; + margin-top: 2em; position: absolute; width: 100%; } diff --git a/themes/default/js/ui.init.js b/themes/default/js/ui.init.js index 29680a48..9d8acf28 100644 --- a/themes/default/js/ui.init.js +++ b/themes/default/js/ui.init.js @@ -86,7 +86,6 @@ $(document).ready(function() { duration: 1000, hash: true }); - } // Add hover state for buttons @@ -103,16 +102,30 @@ $(document).ready(function() { // @todo apply hover affect to links $(".gItem").hover( function(){ - var pos = $(this).position(); - var itemClasses = $(this).attr("class"); - var bgColor = $(this).css("background-color"); - var cont = $(this).parent(); + var position = $(this).position(); + var item_classes = $(this).attr("class"); + var bg_color = $(this).css("background-color"); + var container = $(this).parent(); $("#gHoverItem").remove(); - cont.append("
                          " + container.append("
                          " + $(this).html() + "
                          "); - $("#gHoverItem").css("top", pos.top); - $("#gHoverItem").css("left", pos.left); - $("#gHoverItem").css("background-color", bgColor); + $("#gHoverItem").css("top", position.top); + $("#gHoverItem").css("left", position.left); + $("#gHoverItem").css("background-color", bg_color); + + var v_align = $(this).find(".gValign"); + var title = $(this).find("h2"); + var meta = $(this).find(".gMetadata"); + var context = $(this).find(".gContextMenu"); + var context_label = $(this).find(".gContextMenu li:first"); + $("#gHoverItem .gItem").height( + $(v_align).gallery_height() + + $(title).gallery_height() + + $(meta).gallery_height() + + parseInt($(context).css("margin-top").replace("px","")) + + $(context_label).gallery_height() + ); + $("#gHoverItem").fadeIn("fast"); $("#gHoverItem").hover( function(){ @@ -138,4 +151,11 @@ $(document).ready(function() { } ); + $.fn.gallery_height = function() { + var ht = $(this).height(); + var mt = $(this).css("margin-top").replace("px",""); + var mb = $(this).css("margin-bottom").replace("px",""); + return ht + parseInt(mt) + parseInt(mb); + }; + }); -- cgit v1.2.3 From 1c4e1344c6899f1abbfd914d36e7686afec2e5cc Mon Sep 17 00:00:00 2001 From: Bharat Mediratta Date: Sun, 9 Aug 2009 12:14:17 -0700 Subject: Update photo_menu() and context_menu() to work with recent menu changes. --- modules/digibug/helpers/digibug_event.php | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/modules/digibug/helpers/digibug_event.php b/modules/digibug/helpers/digibug_event.php index 93bc1747..c75eed49 100644 --- a/modules/digibug/helpers/digibug_event.php +++ b/modules/digibug/helpers/digibug_event.php @@ -28,23 +28,21 @@ class digibug_event_Core { static function photo_menu($menu, $theme) { $item = $theme->item(); - $menu->get("options_menu") - ->append(Menu::factory("link") - ->id("digibug") - ->label(t("Print with Digibug")) - ->url(url::site("digibug/print_photo/$item->id?csrf=$theme->csrf")) - ->css_id("gDigibugLink")); + $menu->append(Menu::factory("link") + ->id("digibug") + ->label(t("Print with Digibug")) + ->url(url::site("digibug/print_photo/$item->id?csrf=$theme->csrf")) + ->css_id("gDigibugLink")); } static function context_menu($menu, $theme, $item) { $item = $theme->item(); if ($item->type == "photo") { - $menu->get("options_menu") - ->append(Menu::factory("link") - ->id("digibug") - ->label(t("Print with Digibug")) - ->url(url::site("digibug/print_photo/$item->id?csrf=$theme->csrf")) - ->css_id("gDigibugLink")); + $menu->append(Menu::factory("link") + ->id("digibug") + ->label(t("Print with Digibug")) + ->url(url::site("digibug/print_photo/$item->id?csrf=$theme->csrf")) + ->css_id("gDigibugLink")); } } } -- cgit v1.2.3 From 85afa537df540bf60ea58029b8954753903f53e6 Mon Sep 17 00:00:00 2001 From: Chad Kieffer Date: Sun, 9 Aug 2009 13:56:39 -0600 Subject: Add jquery ui print icon class to menu --- modules/digibug/helpers/digibug_event.php | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/modules/digibug/helpers/digibug_event.php b/modules/digibug/helpers/digibug_event.php index c75eed49..b257d16c 100644 --- a/modules/digibug/helpers/digibug_event.php +++ b/modules/digibug/helpers/digibug_event.php @@ -32,17 +32,19 @@ class digibug_event_Core { ->id("digibug") ->label(t("Print with Digibug")) ->url(url::site("digibug/print_photo/$item->id?csrf=$theme->csrf")) - ->css_id("gDigibugLink")); + ->css_id("gDigibugLink") + ->css_class("ui-icon-print")); } - static function context_menu($menu, $theme, $item) { + static function context_menu($menu, $theme) { $item = $theme->item(); if ($item->type == "photo") { $menu->append(Menu::factory("link") ->id("digibug") ->label(t("Print with Digibug")) ->url(url::site("digibug/print_photo/$item->id?csrf=$theme->csrf")) - ->css_id("gDigibugLink")); + ->css_id("gDigibugLink") + ->css_class("ui-icon-print")); } } } -- cgit v1.2.3 From 13546d0be70764af812bb52c6022c4eeb0438ac0 Mon Sep 17 00:00:00 2001 From: Chad Kieffer Date: Sun, 9 Aug 2009 13:59:48 -0600 Subject: Fixed case --- modules/gallery/helpers/gallery.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/gallery/helpers/gallery.php b/modules/gallery/helpers/gallery.php index 72e7aeeb..0bf180c1 100644 --- a/modules/gallery/helpers/gallery.php +++ b/modules/gallery/helpers/gallery.php @@ -227,7 +227,7 @@ class gallery_Core { $options_menu->append(Menu::factory("dialog") ->id("edit") ->label($edit_title) - ->css_clasS("ui-icon-pencil") + ->css_class("ui-icon-pencil") ->url(url::site("quick/form_edit/$item->id?page_type=$page_type"))); -- cgit v1.2.3 From a961211f569d51631a8ac12327cb72b4818c4853 Mon Sep 17 00:00:00 2001 From: Chad Kieffer Date: Sun, 9 Aug 2009 22:51:21 -0600 Subject: Move the get photo filter out to it's own function for re-use. Docblock cleanup. --- lib/gallery.common.js | 38 ++++++++++++++++++++++++++++++-------- 1 file changed, 30 insertions(+), 8 deletions(-) diff --git a/lib/gallery.common.js b/lib/gallery.common.js index b1160e31..3a4d3c0a 100644 --- a/lib/gallery.common.js +++ b/lib/gallery.common.js @@ -55,20 +55,42 @@ /** * Reduce the width of an image if it's wider than its parent container - * @param elementID The image's container + * @param elementID The image container's ID */ $.fn.gallery_fit_image = function() { - var photo = $(this).find("img").filter(function() { - return this.id.match(/gPhotoId-\d+/); - }); - var cont_width = $(this).width(); + var container_width = $(this).width(); + var photo = $(this).gallery_get_photo(); var photo_width = photo.width(); - if (cont_width < photo_width) { - var proportion = cont_width / photo_width; - photo.width(cont_width); + if (container_width < photo_width) { + var proportion = container_width / photo_width; + photo.width(container_width); photo.height(proportion * photo.height()); } }; + /** + * Get a thumbnail or resize photo within a container + * @param elementID The image container's ID + * @return object + */ + $.fn.gallery_get_photo = function() { + var photo = $(this).find("img").filter(function() { + return this.id.match(/gPhotoId-\d+/); + }); + return photo; + } + + /** + * Get the sum of an element's height, margin-top, and margin-bottom + * @param elementID the element's ID + * @return int + */ + $.fn.gallery_height = function() { + var ht = $(this).height(); + var mt = $(this).css("margin-top").replace("px",""); + var mb = $(this).css("margin-bottom").replace("px",""); + return ht + parseInt(mt) + parseInt(mb); + }; + })(jQuery); -- cgit v1.2.3 From 69b7b1803a73090429efd09299ea15d73102f34c Mon Sep 17 00:00:00 2001 From: Chad Kieffer Date: Sun, 9 Aug 2009 23:08:18 -0600 Subject: Move hover effect to a function. --- lib/gallery.common.js | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/lib/gallery.common.js b/lib/gallery.common.js index 3a4d3c0a..8a769327 100644 --- a/lib/gallery.common.js +++ b/lib/gallery.common.js @@ -92,5 +92,17 @@ return ht + parseInt(mt) + parseInt(mb); }; + // Add hover state to buttons + $.fn.gallery_hover_init = function() { + $(".ui-state-default").hover( + function(){ + $(this).addClass("ui-state-hover"); + }, + function(){ + $(this).removeClass("ui-state-hover"); + } + ); + } + })(jQuery); -- cgit v1.2.3 From 24e29b0b68c364239bf79d7224e1f3dd3ac2c8a1 Mon Sep 17 00:00:00 2001 From: Chad Kieffer Date: Sun, 9 Aug 2009 23:10:02 -0600 Subject: Rename fit_image to fit_photo for consistency. --- lib/gallery.common.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/gallery.common.js b/lib/gallery.common.js index 8a769327..4db316c0 100644 --- a/lib/gallery.common.js +++ b/lib/gallery.common.js @@ -57,7 +57,7 @@ * Reduce the width of an image if it's wider than its parent container * @param elementID The image container's ID */ - $.fn.gallery_fit_image = function() { + $.fn.gallery_fit_photo = function() { var container_width = $(this).width(); var photo = $(this).gallery_get_photo(); var photo_width = photo.width(); -- cgit v1.2.3 From c85d9b41d9fdc7f6ca19386f5eedbd2dea119b46 Mon Sep 17 00:00:00 2001 From: Chad Kieffer Date: Sun, 9 Aug 2009 23:12:25 -0600 Subject: First stab at context menu for resize. It's quirky and needs work. --- themes/default/js/ui.init.js | 153 ++++++++++++++++++++++--------------------- 1 file changed, 78 insertions(+), 75 deletions(-) diff --git a/themes/default/js/ui.init.js b/themes/default/js/ui.init.js index 9d8acf28..3726d305 100644 --- a/themes/default/js/ui.init.js +++ b/themes/default/js/ui.init.js @@ -49,11 +49,8 @@ $(document).ready(function() { // Apply jQuery UI button css to submit inputs $("input[type=submit]:not(.gShortForm input)").addClass("ui-state-default ui-corner-all"); - // Album view only - if ($("#gAlbumGrid").length) { - // Vertical align thumbnails/metadata in album grid - $(".gItem").gallery_valign(); - // Apply styles to gContextMenu + // Apply styles and icon classes to gContextMenu + if ($(".gContextMenu").length) { $(".gContextMenu li").addClass("ui-state-default"); $(".gContextMenu a").addClass("gButtonLink ui-icon-left"); $(".gContextMenu a").prepend(""); @@ -63,10 +60,83 @@ $(document).ready(function() { }); } + // Album view only + if ($("#gAlbumGrid").length) { + // Vertical align thumbnails/metadata in album grid + $(".gItem").gallery_valign(); + + // Initialize context menus + $(".gItem").hover( + function(){ + var position = $(this).position(); + var item_classes = $(this).attr("class"); + var bg_color = $(this).css("background-color"); + var container = $(this).parent(); + $("#gHoverItem").remove(); + container.append("
                          " + + $(this).html() + "
                          "); + $("#gHoverItem").css("top", position.top); + $("#gHoverItem").css("left", position.left); + $("#gHoverItem").css("background-color", bg_color); + $.fn.gallery_hover_init(); + var v_align = $(this).find(".gValign"); + var title = $(this).find("h2"); + var meta = $(this).find(".gMetadata"); + var context = $(this).find(".gContextMenu"); + var context_label = $(this).find(".gContextMenu li:first"); + $("#gHoverItem .gItem").height( + $(v_align).gallery_height() + + $(title).gallery_height() + + $(meta).gallery_height() + + parseInt($(context).css("margin-top").replace("px","")) + + $(context_label).gallery_height() + ); + + $("#gHoverItem").fadeIn("fast"); + $("#gHoverItem").hover( + function(){ + // Initialize context menus + $(".gContextMenu ul").hide(); + $(".gContextMenu").hover( + function() { + $(this).find("ul").slideDown("fast"); + var dialogLinks = $(this).find(".gDialogLink"); + $(dialogLinks).gallery_dialog(); + }, + function() { + $(this).find("ul").slideUp("slow"); + } + ); + }, + function() { + $(this).hide(); + } + ); + } + ); + } + // Photo/Item item view if ($("#gItem").length) { // Ensure the resized image fits within its container - $("#gItem").gallery_fit_image(); + $("#gItem").gallery_fit_photo(); + + // Initialize context menus + var resize = $("#gItem").gallery_get_photo(); + $(resize).hover( + function(){ + $(".gContextMenu").hover( + function() { + $(this).find("ul").slideDown("fast"); + var dialogLinks = $(this).find(".gDialogLink"); + $(dialogLinks).gallery_dialog(); + }, + function() { + $(this).find("ul").slideUp("slow"); + } + ); + } + ); // Collapse comments form, insert button to expand if ($("#gAddCommentForm").length) { @@ -88,74 +158,7 @@ $(document).ready(function() { }); } - // Add hover state for buttons - $(".ui-state-default").hover( - function(){ - $(this).addClass("ui-state-hover"); - }, - function(){ - $(this).removeClass("ui-state-hover"); - } - ); - - // Initialize context menus - // @todo apply hover affect to links - $(".gItem").hover( - function(){ - var position = $(this).position(); - var item_classes = $(this).attr("class"); - var bg_color = $(this).css("background-color"); - var container = $(this).parent(); - $("#gHoverItem").remove(); - container.append("
                          " - + $(this).html() + "
                          "); - $("#gHoverItem").css("top", position.top); - $("#gHoverItem").css("left", position.left); - $("#gHoverItem").css("background-color", bg_color); - - var v_align = $(this).find(".gValign"); - var title = $(this).find("h2"); - var meta = $(this).find(".gMetadata"); - var context = $(this).find(".gContextMenu"); - var context_label = $(this).find(".gContextMenu li:first"); - $("#gHoverItem .gItem").height( - $(v_align).gallery_height() - + $(title).gallery_height() - + $(meta).gallery_height() - + parseInt($(context).css("margin-top").replace("px","")) - + $(context_label).gallery_height() - ); - - $("#gHoverItem").fadeIn("fast"); - $("#gHoverItem").hover( - function(){ - // Initialize context menus - $(".gContextMenu ul").hide(); - $(".gContextMenu").hover( - function() { - $(this).find("ul").slideDown("fast"); - var dialogLinks = $(this).find(".gDialogLink"); - $(dialogLinks).gallery_dialog(); - }, - function() { - $(this).find("ul").slideUp("slow"); - } - ); - }, - function() { - $(this).hide(); - } - ); - }, - function(){ - } - ); - - $.fn.gallery_height = function() { - var ht = $(this).height(); - var mt = $(this).css("margin-top").replace("px",""); - var mb = $(this).css("margin-bottom").replace("px",""); - return ht + parseInt(mt) + parseInt(mb); - }; + // Initialize button hover effect + $.fn.gallery_hover_init(); }); -- cgit v1.2.3 From cea1d4f1f3d295284f3ba19f0d73bb2785b6ed29 Mon Sep 17 00:00:00 2001 From: Chad Kieffer Date: Sun, 9 Aug 2009 23:32:53 -0600 Subject: Forgot to commit the css for the resize photo view context menu. --- themes/default/css/screen.css | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/themes/default/css/screen.css b/themes/default/css/screen.css index 6a29e95f..5ab9083d 100644 --- a/themes/default/css/screen.css +++ b/themes/default/css/screen.css @@ -515,6 +515,7 @@ form .gError, /* Individual photo content ~~~~~~~~~~~~~~ */ #gContent #gItem { + position: relative; width: 99%; } @@ -616,14 +617,25 @@ form .gError, /* Context Menu ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ .gContextMenu { + position: absolute; bottom: 0; - display: none; left: 0; +} + +.gItem .gContextMenu { + display: none; margin-top: 2em; - position: absolute; width: 100%; } +#gItem .gContextMenu { + font-size: .7em; +} + +#gItem .gContextMenu ul { + display: none; +} + .gContextMenu li { border-left: none; border-right: none; -- cgit v1.2.3 From f7a23e0a9cdd4a85e4bc50964917d6995b7d54ab Mon Sep 17 00:00:00 2001 From: Bharat Mediratta Date: Sun, 9 Aug 2009 23:08:35 -0700 Subject: Fix up context menus a bit. - Update digibug_event::context_menu() to take the actual item - Change gallery::context_menu() to not require the page_type as an argument --- modules/digibug/helpers/digibug_event.php | 16 ++++++++-------- modules/gallery/helpers/gallery.php | 7 ++++--- modules/gallery/libraries/Theme_View.php | 5 ++--- 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/modules/digibug/helpers/digibug_event.php b/modules/digibug/helpers/digibug_event.php index b257d16c..d2830b80 100644 --- a/modules/digibug/helpers/digibug_event.php +++ b/modules/digibug/helpers/digibug_event.php @@ -36,15 +36,15 @@ class digibug_event_Core { ->css_class("ui-icon-print")); } - static function context_menu($menu, $theme) { - $item = $theme->item(); + static function context_menu($menu, $theme, $item) { if ($item->type == "photo") { - $menu->append(Menu::factory("link") - ->id("digibug") - ->label(t("Print with Digibug")) - ->url(url::site("digibug/print_photo/$item->id?csrf=$theme->csrf")) - ->css_id("gDigibugLink") - ->css_class("ui-icon-print")); + $menu->get("options_menu") + ->append(Menu::factory("link") + ->id("digibug") + ->label(t("Print with Digibug")) + ->url(url::site("digibug/print_photo/$item->id?csrf=$theme->csrf")) + ->css_id("gDigibugLink") + ->css_class("ui-icon-print")); } } } diff --git a/modules/gallery/helpers/gallery.php b/modules/gallery/helpers/gallery.php index 0bf180c1..279f2013 100644 --- a/modules/gallery/helpers/gallery.php +++ b/modules/gallery/helpers/gallery.php @@ -197,7 +197,8 @@ class gallery_Core { return $menu; } - static function context_menu($menu, $theme, $item, $page_type) { + static function context_menu($menu, $theme, $item) { + $page_type = $theme->page_type(); switch ($item->type) { case "movie": $edit_title = t("Edit this movie"); @@ -218,9 +219,9 @@ class gallery_Core { $move_title = t("Move to another album"); $csrf = access::csrf_token(); - + $menu->append($options_menu = Menu::factory("submenu") - ->id("options") + ->id("options_menu") ->label(t("Options")) ->css_class("ui-icon-carat-1-n")); diff --git a/modules/gallery/libraries/Theme_View.php b/modules/gallery/libraries/Theme_View.php index 24dea729..a5f5db03 100644 --- a/modules/gallery/libraries/Theme_View.php +++ b/modules/gallery/libraries/Theme_View.php @@ -118,9 +118,8 @@ class Theme_View_Core extends Gallery_View { ->label(t("Options"))) ->css_class("gContextMenu"); - $page_type = Input::instance()->get("page_type"); - gallery::context_menu($menu, $this, $item, $page_type); - module::event("context_menu", $menu, $this, $item, $page_type); + gallery::context_menu($menu, $this, $item); + module::event("context_menu", $menu, $this, $item); return $menu->compact(); } -- cgit v1.2.3 From 351532d858b8071e23176bf3bf0eff8a5eab53f6 Mon Sep 17 00:00:00 2001 From: Bharat Mediratta Date: Mon, 10 Aug 2009 10:07:54 -0700 Subject: Fix indentation. --- modules/gallery/helpers/gallery.php | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/modules/gallery/helpers/gallery.php b/modules/gallery/helpers/gallery.php index 279f2013..42097a99 100644 --- a/modules/gallery/helpers/gallery.php +++ b/modules/gallery/helpers/gallery.php @@ -226,21 +226,21 @@ class gallery_Core { ->css_class("ui-icon-carat-1-n")); $options_menu->append(Menu::factory("dialog") - ->id("edit") - ->label($edit_title) - ->css_class("ui-icon-pencil") - ->url(url::site("quick/form_edit/$item->id?page_type=$page_type"))); + ->id("edit") + ->label($edit_title) + ->css_class("ui-icon-pencil") + ->url(url::site("quick/form_edit/$item->id?page_type=$page_type"))); if ($item->is_photo() && graphics::can("rotate")) { $options_menu ->append(Menu::factory("link") - ->id("rotate_ccw") + ->id("rotate_ccw") ->label(t("Rotate 90° counter clockwise")) ->css_class("ui-icon-rotate-ccw") ->url(url::site("quick/rotate/$item->id/ccw?csrf=$csrf&page_type=$page_type"))) ->append(Menu::factory("link") - ->id("rotate_cw") + ->id("rotate_cw") ->label(t("Rotate 90° clockwise")) ->css_class("ui-icon-rotate-cw") ->url(url::site("quick/rotate/$item->id/cw?csrf=$csrf&page_type=$page_type"))); -- cgit v1.2.3 From 790545ac97358dd92ce954e617d5255e6644c1a7 Mon Sep 17 00:00:00 2001 From: Bharat Mediratta Date: Mon, 10 Aug 2009 10:49:50 -0700 Subject: Add missing semicolons. --- lib/gallery.common.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/gallery.common.js b/lib/gallery.common.js index 4db316c0..fdb7a1cc 100644 --- a/lib/gallery.common.js +++ b/lib/gallery.common.js @@ -78,7 +78,7 @@ return this.id.match(/gPhotoId-\d+/); }); return photo; - } + }; /** * Get the sum of an element's height, margin-top, and margin-bottom @@ -102,7 +102,7 @@ $(this).removeClass("ui-state-hover"); } ); - } + }; })(jQuery); -- cgit v1.2.3 From e3a58b76c14c64a5254f4efd73730866818bd0b3 Mon Sep 17 00:00:00 2001 From: Chad Kieffer Date: Mon, 10 Aug 2009 23:11:31 -0600 Subject: Return .each() to work with more than an individual photo. --- lib/gallery.common.js | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/lib/gallery.common.js b/lib/gallery.common.js index 4db316c0..eea0fada 100644 --- a/lib/gallery.common.js +++ b/lib/gallery.common.js @@ -58,14 +58,16 @@ * @param elementID The image container's ID */ $.fn.gallery_fit_photo = function() { - var container_width = $(this).width(); - var photo = $(this).gallery_get_photo(); - var photo_width = photo.width(); - if (container_width < photo_width) { - var proportion = container_width / photo_width; - photo.width(container_width); - photo.height(proportion * photo.height()); - } + return this.each(function(i) { + var container_width = $(this).width(); + var photo = $(this).gallery_get_photo(); + var photo_width = photo.width(); + if (container_width < photo_width) { + var proportion = container_width / photo_width; + photo.width(container_width); + photo.height(proportion * photo.height()); + } + }); }; /** -- cgit v1.2.3 From cbba45fffc7368280e9529f55e108d0080175b6a Mon Sep 17 00:00:00 2001 From: Bharat Mediratta Date: Mon, 10 Aug 2009 23:05:05 -0700 Subject: Create the concept of an "ajax link" and use it for thumbnail rotation and album covers in the context menu. Notes: - This requires context_menu() to have a CSS selector that refers to the that we're operating on, otherwise we don't know how to find the thumbnail, etc. - Create Menu_Element_Ajax_Link which has an ajax_handler attribute that contains a snippet of JS that we're going to run when the ajax call returns. - Add $.gallery_replace_image in gallery.common.js - Add lib/gallery.ajax.js which can be used to ajaxify any link, and have ui.init.js in the themes call that on all .gAjaxLink elements. --- lib/gallery.ajax.js | 15 +++ lib/gallery.common.js | 4 + modules/gallery/helpers/gallery.php | 191 ++++++++++++++++-------------- modules/gallery/libraries/Menu.php | 34 ++++++ modules/gallery/libraries/Theme_View.php | 6 +- themes/admin_default/js/ui.init.js | 3 + themes/admin_default/views/admin.html.php | 1 + themes/default/js/ui.init.js | 9 +- themes/default/views/album.html.php | 2 +- themes/default/views/movie.html.php | 2 +- themes/default/views/page.html.php | 1 + themes/default/views/photo.html.php | 2 +- 12 files changed, 169 insertions(+), 101 deletions(-) create mode 100644 lib/gallery.ajax.js diff --git a/lib/gallery.ajax.js b/lib/gallery.ajax.js new file mode 100644 index 00000000..4f26745d --- /dev/null +++ b/lib/gallery.ajax.js @@ -0,0 +1,15 @@ +(function($) { + $.widget("ui.gallery_ajax", { + _init: function() { + this.element.click(function(event) { + eval("var ajax_handler = " + $(event.currentTarget).attr("ajax_handler")); + $.get($(event.currentTarget).attr("href"), function(data) { + eval("var data = " + data); + ajax_handler(data); + }); + event.preventDefault(); + return false; + }); + } + }); +})(jQuery); diff --git a/lib/gallery.common.js b/lib/gallery.common.js index fdb7a1cc..53c2fafb 100644 --- a/lib/gallery.common.js +++ b/lib/gallery.common.js @@ -104,5 +104,9 @@ ); }; + // Ajax handler for replacing an image, used in Ajax thumbnail rotation + $.gallery_replace_image = function(data, thumb) { + $(thumb).attr({src: data.src, width: data.width, height: data.height}); + }; })(jQuery); diff --git a/modules/gallery/helpers/gallery.php b/modules/gallery/helpers/gallery.php index 42097a99..c81af842 100644 --- a/modules/gallery/helpers/gallery.php +++ b/modules/gallery/helpers/gallery.php @@ -197,108 +197,117 @@ class gallery_Core { return $menu; } - static function context_menu($menu, $theme, $item) { - $page_type = $theme->page_type(); - switch ($item->type) { - case "movie": - $edit_title = t("Edit this movie"); - $delete_title = t("Delete this movie"); - break; - - case "album": - $edit_title = t("Edit this album"); - $delete_title = t("Delete this album"); - break; - - default: - $edit_title = t("Edit this photo"); - $delete_title = t("Delete this photo"); - break; - } - $cover_title = t("Choose as the album cover"); - $move_title = t("Move to another album"); - - $csrf = access::csrf_token(); - + static function context_menu($menu, $theme, $item, $thumb_css_selector) { $menu->append($options_menu = Menu::factory("submenu") ->id("options_menu") ->label(t("Options")) ->css_class("ui-icon-carat-1-n")); - $options_menu->append(Menu::factory("dialog") - ->id("edit") - ->label($edit_title) - ->css_class("ui-icon-pencil") - ->url(url::site("quick/form_edit/$item->id?page_type=$page_type"))); + if (access::can("edit", $item)) { + $page_type = $theme->page_type(); + switch ($item->type) { + case "movie": + $edit_title = t("Edit this movie"); + $delete_title = t("Delete this movie"); + break; + case "album": + $edit_title = t("Edit this album"); + $delete_title = t("Delete this album"); + break; - if ($item->is_photo() && graphics::can("rotate")) { - $options_menu - ->append(Menu::factory("link") - ->id("rotate_ccw") - ->label(t("Rotate 90° counter clockwise")) - ->css_class("ui-icon-rotate-ccw") - ->url(url::site("quick/rotate/$item->id/ccw?csrf=$csrf&page_type=$page_type"))) - ->append(Menu::factory("link") - ->id("rotate_cw") - ->label(t("Rotate 90° clockwise")) - ->css_class("ui-icon-rotate-cw") - ->url(url::site("quick/rotate/$item->id/cw?csrf=$csrf&page_type=$page_type"))); - } + default: + $edit_title = t("Edit this photo"); + $delete_title = t("Delete this photo"); + break; + } + $cover_title = t("Choose as the album cover"); + $move_title = t("Move to another album"); - // Don't move photos from the photo page; we don't yet have a good way of redirecting after move - if ($page_type == "album") { - $options_menu - ->append(Menu::factory("dialog") - ->id("move") - ->label($move_title) - ->css_class("ui-icon-folder-open") - ->url(url::site("move/browse/$item->id"))); - } + $csrf = access::csrf_token(); + + $options_menu->append(Menu::factory("dialog") + ->id("edit") + ->label($edit_title) + ->css_class("ui-icon-pencil") + ->url(url::site("quick/form_edit/$item->id?page_type=$page_type"))); - $parent = $item->parent(); - if (access::can("edit", $parent)) { - // We can't make this item the highlight if it's an album with no album cover, or if it's - // already the album cover. - if (($item->type == "album" && empty($item->album_cover_item_id)) || - ($item->type == "album" && $parent->album_cover_item_id == $item->album_cover_item_id) || - $parent->album_cover_item_id == $item->id) { - $disabledState = " ui-state-disabled"; - } else { - $disabledState = " "; + + if ($item->is_photo() && graphics::can("rotate")) { + $options_menu + ->append( + Menu::factory("ajax_link") + ->id("rotate_ccw") + ->label(t("Rotate 90° counter clockwise")) + ->css_class("ui-icon-rotate-ccw") + ->ajax_handler("function(data) { " . + "\$.gallery_replace_image(data, \$('$thumb_css_selector')) }") + ->url(url::site("quick/rotate/$item->id/ccw?csrf=$csrf&page_type=$page_type"))) + ->append( + Menu::factory("ajax_link") + ->id("rotate_cw") + ->label(t("Rotate 90° clockwise")) + ->css_class("ui-icon-rotate-cw") + ->ajax_handler("function(data) { " . + "\$.gallery_replace_image(data, \$('$thumb_css_selector')) }") + ->url(url::site("quick/rotate/$item->id/cw?csrf=$csrf&page_type=$page_type"))); + } + + // Don't move photos from the photo page; we don't yet have a good way of redirecting after + // move + if ($page_type == "album") { + $options_menu + ->append(Menu::factory("dialog") + ->id("move") + ->label($move_title) + ->css_class("ui-icon-folder-open") + ->url(url::site("move/browse/$item->id"))); } - $options_menu - ->append(Menu::factory("link") - ->id("make_album_cover") - ->label($cover_title) - ->css_class("ui-icon-star") - ->url( - url::site("quick/make_album_cover/$item->id?csrf=$csrf&page_type=$page_type"))) - ->append(Menu::factory("dialog") - ->id("delete") - ->label($delete_title) - ->css_class("ui-icon-trash") - ->css_id("gQuickDelete") - ->url(url::site("quick/form_delete/$item->id?csrf=$csrf&page_type=$page_type"))); - } - if ($item->is_album()) { - $options_menu - ->append(Menu::factory("dialog") - ->id("add_item") - ->label(t("Add a photo")) - ->css_class("add_item") - ->url(url::site("simple_uploader/app/$item->id"))) - ->append(Menu::factory("dialog") - ->id("add_album") - ->label(t("Add an album")) - ->css_class("add_album") - ->url(url::site("form/add/albums/$item->id?type=album"))) - ->append(Menu::factory("dialog") - ->id("edit_permissions") - ->label(t("Edit permissions")) - ->css_class("permissions") - ->url(url::site("permissions/browse/$item->id"))); + $parent = $item->parent(); + if (access::can("edit", $parent)) { + // We can't make this item the highlight if it's an album with no album cover, or if it's + // already the album cover. + if (($item->type == "album" && empty($item->album_cover_item_id)) || + ($item->type == "album" && $parent->album_cover_item_id == $item->album_cover_item_id) || + $parent->album_cover_item_id == $item->id) { + $disabledState = " ui-state-disabled"; + } else { + $disabledState = " "; + } + $options_menu + ->append(Menu::factory("ajax_link") + ->id("make_album_cover") + ->label($cover_title) + ->css_class("ui-icon-star") + ->ajax_handler("function(data) { window.location.reload() }") + ->url(url::site("quick/make_album_cover/$item->id?csrf=$csrf"))) + ->append(Menu::factory("dialog") + ->id("delete") + ->label($delete_title) + ->css_class("ui-icon-trash") + ->css_id("gQuickDelete") + ->url(url::site("quick/form_delete/$item->id?csrf=$csrf&page_type=$page_type"))); + } + + if ($item->is_album()) { + $options_menu + ->append(Menu::factory("dialog") + ->id("add_item") + ->label(t("Add a photo")) + ->css_class("add_item") + ->url(url::site("simple_uploader/app/$item->id"))) + ->append(Menu::factory("dialog") + ->id("add_album") + ->label(t("Add an album")) + ->css_class("add_album") + ->url(url::site("form/add/albums/$item->id?type=album"))) + ->append(Menu::factory("dialog") + ->id("edit_permissions") + ->label(t("Edit permissions")) + ->css_class("permissions") + ->url(url::site("permissions/browse/$item->id"))); + } } } } \ No newline at end of file diff --git a/modules/gallery/libraries/Menu.php b/modules/gallery/libraries/Menu.php index 263dc38d..07b2b2b8 100644 --- a/modules/gallery/libraries/Menu.php +++ b/modules/gallery/libraries/Menu.php @@ -96,6 +96,37 @@ class Menu_Element_Link extends Menu_Element { } } +/** + * Menu element that provides an AJAX link. + */ +class Menu_Element_Ajax_Link extends Menu_Element { + public $ajax_handler; + + /** + * Set the AJAX handler + * @chainable + */ + public function ajax_handler($ajax_handler) { + $this->ajax_handler = $ajax_handler; + return $this; + } + + public function __toString() { + if (isset($this->css_id) && !empty($this->css_id)) { + $css_id = " id=\"$this->css_id\""; + } else { + $css_id = ""; + } + if (isset($this->css_class) && !empty($this->css_class)) { + $css_class = " $this->css_class"; + } else { + $css_class = ""; + } + return "
                        • url\" " . + "title=\"$this->label\" ajax_handler=\"$this->ajax_handler\">$this->label
                        • "; + } +} + /** * Menu element that provides a pop-up dialog */ @@ -132,6 +163,9 @@ class Menu_Core extends Menu_Element { case "link": return new Menu_Element_Link($type); + case "ajax_link": + return new Menu_Element_Ajax_Link($type); + case "dialog": return new Menu_Element_Dialog($type); diff --git a/modules/gallery/libraries/Theme_View.php b/modules/gallery/libraries/Theme_View.php index a5f5db03..541bce88 100644 --- a/modules/gallery/libraries/Theme_View.php +++ b/modules/gallery/libraries/Theme_View.php @@ -111,15 +111,15 @@ class Theme_View_Core extends Gallery_View { return $menu->compact(); } - public function context_menu($item) { + public function context_menu($item, $thumbnail_css_selector) { $menu = Menu::factory("root") ->append(Menu::factory("submenu") ->id("context_menu") ->label(t("Options"))) ->css_class("gContextMenu"); - gallery::context_menu($menu, $this, $item); - module::event("context_menu", $menu, $this, $item); + gallery::context_menu($menu, $this, $item, $thumbnail_css_selector); + module::event("context_menu", $menu, $this, $item, $thumbnail_css_selector); return $menu->compact(); } diff --git a/themes/admin_default/js/ui.init.js b/themes/admin_default/js/ui.init.js index e52f0c4c..daa6dd70 100644 --- a/themes/admin_default/js/ui.init.js +++ b/themes/admin_default/js/ui.init.js @@ -19,6 +19,9 @@ $(document).ready(function(){ // Initialize modal dialogs $(".gDialogLink").gallery_dialog(); + // Initialize ajax links + $(".gDialogLink").gallery_ajax(); + // Initialize panels $(".gPanelLink").gallery_panel(); diff --git a/themes/admin_default/views/admin.html.php b/themes/admin_default/views/admin.html.php index d27f9260..3f4128cb 100644 --- a/themes/admin_default/views/admin.html.php +++ b/themes/admin_default/views/admin.html.php @@ -25,6 +25,7 @@ + script("gallery.ajax.js") ?> script("gallery.dialog.js") ?> script("superfish/js/superfish.js") ?> script("jquery.dropshadow.js") ?> diff --git a/themes/default/js/ui.init.js b/themes/default/js/ui.init.js index 3726d305..60482972 100644 --- a/themes/default/js/ui.init.js +++ b/themes/default/js/ui.init.js @@ -34,6 +34,7 @@ $(document).ready(function() { // Initialize dialogs $("#gLoginLink").addClass("gDialogLink"); $(".gDialogLink").gallery_dialog(); + $(".gAjaxLink").gallery_ajax(); // Initialize view menu if ($("#gViewMenu").length) { @@ -100,8 +101,8 @@ $(document).ready(function() { $(".gContextMenu").hover( function() { $(this).find("ul").slideDown("fast"); - var dialogLinks = $(this).find(".gDialogLink"); - $(dialogLinks).gallery_dialog(); + $(this).find(".gDialogLink").gallery_dialog(); + $(this).find(".gAjaxLink").gallery_ajax(); }, function() { $(this).find("ul").slideUp("slow"); @@ -128,8 +129,8 @@ $(document).ready(function() { $(".gContextMenu").hover( function() { $(this).find("ul").slideDown("fast"); - var dialogLinks = $(this).find(".gDialogLink"); - $(dialogLinks).gallery_dialog(); + $(this).find(".gDialogLink").gallery_dialog(); + $(this).find(".gAjaxLink").gallery_ajax(); }, function() { $(this).find("ul").slideUp("slow"); diff --git a/themes/default/views/album.html.php b/themes/default/views/album.html.php index ce57458e..e2890482 100644 --- a/themes/default/views/album.html.php +++ b/themes/default/views/album.html.php @@ -19,7 +19,7 @@ thumb_img(array("class" => "gThumbnail")) ?> thumb_bottom($child) ?> - context_menu($child) ?> + context_menu($child, "#gItemId-{$child->id} .gThumbnail") ?>

                          title) ?>

                          diff --git a/themes/default/views/page.html.php b/themes/default/views/page.html.php index 66282bae..2cb71b9e 100644 --- a/themes/default/views/page.html.php +++ b/themes/default/views/page.html.php @@ -53,6 +53,7 @@ + script("gallery.ajax.js") ?> script("gallery.dialog.js") ?> script("gallery.form.js") ?> script("superfish/js/superfish.js") ?> diff --git a/themes/default/views/photo.html.php b/themes/default/views/photo.html.php index 453417dc..fa5def47 100644 --- a/themes/default/views/photo.html.php +++ b/themes/default/views/photo.html.php @@ -47,7 +47,7 @@ resize_bottom($item) ?> - context_menu($item) ?> + context_menu($item, "#gPhotoId-{$item->id}") ?>
                          -- cgit v1.2.3 From a10c309c36b0c5e8adf55cde8ffb2dd093938ea5 Mon Sep 17 00:00:00 2001 From: Chad Kieffer Date: Tue, 11 Aug 2009 00:28:38 -0600 Subject: Replace tabs w/ spaces. --- lib/gallery.ajax.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/lib/gallery.ajax.js b/lib/gallery.ajax.js index 4f26745d..31039ea4 100644 --- a/lib/gallery.ajax.js +++ b/lib/gallery.ajax.js @@ -2,13 +2,13 @@ $.widget("ui.gallery_ajax", { _init: function() { this.element.click(function(event) { - eval("var ajax_handler = " + $(event.currentTarget).attr("ajax_handler")); - $.get($(event.currentTarget).attr("href"), function(data) { - eval("var data = " + data); - ajax_handler(data); + eval("var ajax_handler = " + $(event.currentTarget).attr("ajax_handler")); + $.get($(event.currentTarget).attr("href"), function(data) { + eval("var data = " + data); + ajax_handler(data); }); - event.preventDefault(); - return false; + event.preventDefault(); + return false; }); } }); -- cgit v1.2.3 From 99d7a0c0dbb799ba64d769475a1534650e98e5b6 Mon Sep 17 00:00:00 2001 From: Chad Kieffer Date: Tue, 11 Aug 2009 00:33:15 -0600 Subject: Make each context menu button clickable from side-to-side --- themes/default/css/screen.css | 1 + 1 file changed, 1 insertion(+) diff --git a/themes/default/css/screen.css b/themes/default/css/screen.css index 5ab9083d..55839c57 100644 --- a/themes/default/css/screen.css +++ b/themes/default/css/screen.css @@ -643,6 +643,7 @@ form .gError, } .gContextMenu li a { + display: block; line-height: 1.6em; } -- cgit v1.2.3 From 65e97fda48620a0808c0cd4414aa9e0656f482ed Mon Sep 17 00:00:00 2001 From: Chad Kieffer Date: Tue, 11 Aug 2009 00:40:14 -0600 Subject: Move context menu to gallery.common --- lib/gallery.common.js | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/lib/gallery.common.js b/lib/gallery.common.js index 317a73e7..e00eb62a 100644 --- a/lib/gallery.common.js +++ b/lib/gallery.common.js @@ -110,5 +110,20 @@ $.gallery_replace_image = function(data, thumb) { $(thumb).attr({src: data.src, width: data.width, height: data.height}); }; + + $.fn.gallery_context_menu = function() { + $(".gContextMenu ul").hide(); + $(".gContextMenu").hover( + function() { + $(this).find("ul").slideDown("fast"); + $(this).find(".gDialogLink").gallery_dialog(); + $(this).find(".gAjaxLink").gallery_ajax(); + }, + function() { + $(this).find("ul").slideUp("slow"); + } + ); + }; + })(jQuery); -- cgit v1.2.3 From bb6bf17076eff74ee490d17b510150d68f5faa54 Mon Sep 17 00:00:00 2001 From: Chad Kieffer Date: Tue, 11 Aug 2009 00:41:07 -0600 Subject: Move context menu to gallery.common, forgot to include in prior commit --- themes/default/js/ui.init.js | 31 ++++--------------------------- 1 file changed, 4 insertions(+), 27 deletions(-) diff --git a/themes/default/js/ui.init.js b/themes/default/js/ui.init.js index 60482972..ef7e43d9 100644 --- a/themes/default/js/ui.init.js +++ b/themes/default/js/ui.init.js @@ -34,7 +34,6 @@ $(document).ready(function() { // Initialize dialogs $("#gLoginLink").addClass("gDialogLink"); $(".gDialogLink").gallery_dialog(); - $(".gAjaxLink").gallery_ajax(); // Initialize view menu if ($("#gViewMenu").length) { @@ -96,18 +95,7 @@ $(document).ready(function() { $("#gHoverItem").fadeIn("fast"); $("#gHoverItem").hover( function(){ - // Initialize context menus - $(".gContextMenu ul").hide(); - $(".gContextMenu").hover( - function() { - $(this).find("ul").slideDown("fast"); - $(this).find(".gDialogLink").gallery_dialog(); - $(this).find(".gAjaxLink").gallery_ajax(); - }, - function() { - $(this).find("ul").slideUp("slow"); - } - ); + $(this).gallery_context_menu(); }, function() { $(this).hide(); @@ -124,20 +112,9 @@ $(document).ready(function() { // Initialize context menus var resize = $("#gItem").gallery_get_photo(); - $(resize).hover( - function(){ - $(".gContextMenu").hover( - function() { - $(this).find("ul").slideDown("fast"); - $(this).find(".gDialogLink").gallery_dialog(); - $(this).find(".gAjaxLink").gallery_ajax(); - }, - function() { - $(this).find("ul").slideUp("slow"); - } - ); - } - ); + $(resize).hover(function(){ + $(this).gallery_context_menu(); + }); // Collapse comments form, insert button to expand if ($("#gAddCommentForm").length) { -- cgit v1.2.3 From 39b37cc585b7e5413c472176e880da93a2de4e11 Mon Sep 17 00:00:00 2001 From: Tim Almdal Date: Wed, 12 Aug 2009 14:13:39 -0700 Subject: Use the jquery-ui library that contains a prerelease version of the slectable component --- lib/jquery-ui.js | 533 ++++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 508 insertions(+), 25 deletions(-) diff --git a/lib/jquery-ui.js b/lib/jquery-ui.js index 0c6a0ebe..4939d009 100644 --- a/lib/jquery-ui.js +++ b/lib/jquery-ui.js @@ -45,18 +45,6 @@ jQuery.ui||(function(c){var i=c.fn.remove,d=c.browser.mozilla&&(parseFloat(c.bro * ui.core.js */ (function(c){c.widget("ui.resizable",c.extend({},c.ui.mouse,{_init:function(){var e=this,j=this.options;this.element.addClass("ui-resizable");c.extend(this,{_aspectRatio:!!(j.aspectRatio),aspectRatio:j.aspectRatio,originalElement:this.element,_proportionallyResizeElements:[],_helper:j.helper||j.ghost||j.animate?j.helper||"ui-resizable-helper":null});if(this.element[0].nodeName.match(/canvas|textarea|input|select|button|img/i)){if(/relative/.test(this.element.css("position"))&&c.browser.opera){this.element.css({position:"relative",top:"auto",left:"auto"})}this.element.wrap(c('
                          ').css({position:this.element.css("position"),width:this.element.outerWidth(),height:this.element.outerHeight(),top:this.element.css("top"),left:this.element.css("left")}));this.element=this.element.parent().data("resizable",this.element.data("resizable"));this.elementIsWrapper=true;this.element.css({marginLeft:this.originalElement.css("marginLeft"),marginTop:this.originalElement.css("marginTop"),marginRight:this.originalElement.css("marginRight"),marginBottom:this.originalElement.css("marginBottom")});this.originalElement.css({marginLeft:0,marginTop:0,marginRight:0,marginBottom:0});this.originalResizeStyle=this.originalElement.css("resize");this.originalElement.css("resize","none");this._proportionallyResizeElements.push(this.originalElement.css({position:"static",zoom:1,display:"block"}));this.originalElement.css({margin:this.originalElement.css("margin")});this._proportionallyResize()}this.handles=j.handles||(!c(".ui-resizable-handle",this.element).length?"e,s,se":{n:".ui-resizable-n",e:".ui-resizable-e",s:".ui-resizable-s",w:".ui-resizable-w",se:".ui-resizable-se",sw:".ui-resizable-sw",ne:".ui-resizable-ne",nw:".ui-resizable-nw"});if(this.handles.constructor==String){if(this.handles=="all"){this.handles="n,e,s,w,se,sw,ne,nw"}var k=this.handles.split(",");this.handles={};for(var f=0;f
                          ');if(/sw|se|ne|nw/.test(h)){g.css({zIndex:++j.zIndex})}if("se"==h){g.addClass("ui-icon ui-icon-gripsmall-diagonal-se")}this.handles[h]=".ui-resizable-"+h;this.element.append(g)}}this._renderAxis=function(p){p=p||this.element;for(var m in this.handles){if(this.handles[m].constructor==String){this.handles[m]=c(this.handles[m],this.element).show()}if(this.elementIsWrapper&&this.originalElement[0].nodeName.match(/textarea|input|select|button/i)){var n=c(this.handles[m],this.element),o=0;o=/sw|ne|nw|se|n|s/.test(m)?n.outerHeight():n.outerWidth();var l=["padding",/ne|nw|n/.test(m)?"Top":/se|sw|s/.test(m)?"Bottom":/^e$/.test(m)?"Right":"Left"].join("");p.css(l,o);this._proportionallyResize()}if(!c(this.handles[m]).length){continue}}};this._renderAxis(this.element);this._handles=c(".ui-resizable-handle",this.element).disableSelection();this._handles.mouseover(function(){if(!e.resizing){if(this.className){var i=this.className.match(/ui-resizable-(se|sw|ne|nw|n|e|s|w)/i)}e.axis=i&&i[1]?i[1]:"se"}});if(j.autoHide){this._handles.hide();c(this.element).addClass("ui-resizable-autohide").hover(function(){c(this).removeClass("ui-resizable-autohide");e._handles.show()},function(){if(!e.resizing){c(this).addClass("ui-resizable-autohide");e._handles.hide()}})}this._mouseInit()},destroy:function(){this._mouseDestroy();var d=function(f){c(f).removeClass("ui-resizable ui-resizable-disabled ui-resizable-resizing").removeData("resizable").unbind(".resizable").find(".ui-resizable-handle").remove()};if(this.elementIsWrapper){d(this.element);var e=this.element;e.parent().append(this.originalElement.css({position:e.css("position"),width:e.outerWidth(),height:e.outerHeight(),top:e.css("top"),left:e.css("left")})).end().remove()}this.originalElement.css("resize",this.originalResizeStyle);d(this.originalElement)},_mouseCapture:function(e){var f=false;for(var d in this.handles){if(c(this.handles[d])[0]==e.target){f=true}}return this.options.disabled||!!f},_mouseStart:function(f){var i=this.options,e=this.element.position(),d=this.element;this.resizing=true;this.documentScroll={top:c(document).scrollTop(),left:c(document).scrollLeft()};if(d.is(".ui-draggable")||(/absolute/).test(d.css("position"))){d.css({position:"absolute",top:e.top,left:e.left})}if(c.browser.opera&&(/relative/).test(d.css("position"))){d.css({position:"relative",top:"auto",left:"auto"})}this._renderProxy();var j=b(this.helper.css("left")),g=b(this.helper.css("top"));if(i.containment){j+=c(i.containment).scrollLeft()||0;g+=c(i.containment).scrollTop()||0}this.offset=this.helper.offset();this.position={left:j,top:g};this.size=this._helper?{width:d.outerWidth(),height:d.outerHeight()}:{width:d.width(),height:d.height()};this.originalSize=this._helper?{width:d.outerWidth(),height:d.outerHeight()}:{width:d.width(),height:d.height()};this.originalPosition={left:j,top:g};this.sizeDiff={width:d.outerWidth()-d.width(),height:d.outerHeight()-d.height()};this.originalMousePosition={left:f.pageX,top:f.pageY};this.aspectRatio=(typeof i.aspectRatio=="number")?i.aspectRatio:((this.originalSize.width/this.originalSize.height)||1);var h=c(".ui-resizable-"+this.axis).css("cursor");c("body").css("cursor",h=="auto"?this.axis+"-resize":h);d.addClass("ui-resizable-resizing");this._propagate("start",f);return true},_mouseDrag:function(d){var g=this.helper,f=this.options,l={},p=this,i=this.originalMousePosition,m=this.axis;var q=(d.pageX-i.left)||0,n=(d.pageY-i.top)||0;var h=this._change[m];if(!h){return false}var k=h.apply(this,[d,q,n]),j=c.browser.msie&&c.browser.version<7,e=this.sizeDiff;if(this._aspectRatio||d.shiftKey){k=this._updateRatio(k,d)}k=this._respectSize(k,d);this._propagate("resize",d);g.css({top:this.position.top+"px",left:this.position.left+"px",width:this.size.width+"px",height:this.size.height+"px"});if(!this._helper&&this._proportionallyResizeElements.length){this._proportionallyResize()}this._updateCache(k);this._trigger("resize",d,this.ui());return false},_mouseStop:function(g){this.resizing=false;var h=this.options,l=this;if(this._helper){var f=this._proportionallyResizeElements,d=f.length&&(/textarea/i).test(f[0].nodeName),e=d&&c.ui.hasScroll(f[0],"left")?0:l.sizeDiff.height,j=d?0:l.sizeDiff.width;var m={width:(l.size.width-j),height:(l.size.height-e)},i=(parseInt(l.element.css("left"),10)+(l.position.left-l.originalPosition.left))||null,k=(parseInt(l.element.css("top"),10)+(l.position.top-l.originalPosition.top))||null;if(!h.animate){this.element.css(c.extend(m,{top:k,left:i}))}l.helper.height(l.size.height);l.helper.width(l.size.width);if(this._helper&&!h.animate){this._proportionallyResize()}}c("body").css("cursor","auto");this.element.removeClass("ui-resizable-resizing");this._propagate("stop",g);if(this._helper){this.helper.remove()}return false},_updateCache:function(d){var e=this.options;this.offset=this.helper.offset();if(a(d.left)){this.position.left=d.left}if(a(d.top)){this.position.top=d.top}if(a(d.height)){this.size.height=d.height}if(a(d.width)){this.size.width=d.width}},_updateRatio:function(g,f){var h=this.options,i=this.position,e=this.size,d=this.axis;if(g.height){g.width=(e.height*this.aspectRatio)}else{if(g.width){g.height=(e.width/this.aspectRatio)}}if(d=="sw"){g.left=i.left+(e.width-g.width);g.top=null}if(d=="nw"){g.top=i.top+(e.height-g.height);g.left=i.left+(e.width-g.width)}return g},_respectSize:function(k,f){var i=this.helper,h=this.options,q=this._aspectRatio||f.shiftKey,p=this.axis,s=a(k.width)&&h.maxWidth&&(h.maxWidthk.width),r=a(k.height)&&h.minHeight&&(h.minHeight>k.height);if(g){k.width=h.minWidth}if(r){k.height=h.minHeight}if(s){k.width=h.maxWidth}if(l){k.height=h.maxHeight}var e=this.originalPosition.left+this.originalSize.width,n=this.position.top+this.size.height;var j=/sw|nw|w/.test(p),d=/nw|ne|n/.test(p);if(g&&j){k.left=e-h.minWidth}if(s&&j){k.left=e-h.maxWidth}if(r&&d){k.top=n-h.minHeight}if(l&&d){k.top=n-h.maxHeight}var m=!k.width&&!k.height;if(m&&!k.left&&k.top){k.top=null}else{if(m&&!k.top&&k.left){k.left=null}}return k},_proportionallyResize:function(){var j=this.options;if(!this._proportionallyResizeElements.length){return}var f=this.helper||this.element;for(var e=0;e
                          ');var d=c.browser.msie&&c.browser.version<7,f=(d?1:0),g=(d?2:-1);this.helper.addClass(this._helper).css({width:this.element.outerWidth()+g,height:this.element.outerHeight()+g,position:"absolute",left:this.elementOffset.left-f+"px",top:this.elementOffset.top-f+"px",zIndex:++h.zIndex});this.helper.appendTo("body").disableSelection()}else{this.helper=this.element}},_change:{e:function(f,e,d){return{width:this.originalSize.width+e}},w:function(g,e,d){var i=this.options,f=this.originalSize,h=this.originalPosition;return{left:h.left+e,width:f.width-e}},n:function(g,e,d){var i=this.options,f=this.originalSize,h=this.originalPosition;return{top:h.top+d,height:f.height-d}},s:function(f,e,d){return{height:this.originalSize.height+d}},se:function(f,e,d){return c.extend(this._change.s.apply(this,arguments),this._change.e.apply(this,[f,e,d]))},sw:function(f,e,d){return c.extend(this._change.s.apply(this,arguments),this._change.w.apply(this,[f,e,d]))},ne:function(f,e,d){return c.extend(this._change.n.apply(this,arguments),this._change.e.apply(this,[f,e,d]))},nw:function(f,e,d){return c.extend(this._change.n.apply(this,arguments),this._change.w.apply(this,[f,e,d]))}},_propagate:function(e,d){c.ui.plugin.call(this,e,[d,this.ui()]);(e!="resize"&&this._trigger(e,d,this.ui()))},plugins:{},ui:function(){return{originalElement:this.originalElement,element:this.element,helper:this.helper,position:this.position,size:this.size,originalSize:this.originalSize,originalPosition:this.originalPosition}}}));c.extend(c.ui.resizable,{version:"1.7.2",eventPrefix:"resize",defaults:{alsoResize:false,animate:false,animateDuration:"slow",animateEasing:"swing",aspectRatio:false,autoHide:false,cancel:":input,option",containment:false,delay:0,distance:1,ghost:false,grid:false,handles:"e,s,se",helper:false,maxHeight:null,maxWidth:null,minHeight:10,minWidth:10,zIndex:1000}});c.ui.plugin.add("resizable","alsoResize",{start:function(e,f){var d=c(this).data("resizable"),g=d.options;_store=function(h){c(h).each(function(){c(this).data("resizable-alsoresize",{width:parseInt(c(this).width(),10),height:parseInt(c(this).height(),10),left:parseInt(c(this).css("left"),10),top:parseInt(c(this).css("top"),10)})})};if(typeof(g.alsoResize)=="object"&&!g.alsoResize.parentNode){if(g.alsoResize.length){g.alsoResize=g.alsoResize[0];_store(g.alsoResize)}else{c.each(g.alsoResize,function(h,i){_store(h)})}}else{_store(g.alsoResize)}},resize:function(f,h){var e=c(this).data("resizable"),i=e.options,g=e.originalSize,k=e.originalPosition;var j={height:(e.size.height-g.height)||0,width:(e.size.width-g.width)||0,top:(e.position.top-k.top)||0,left:(e.position.left-k.left)||0},d=function(l,m){c(l).each(function(){var p=c(this),q=c(this).data("resizable-alsoresize"),o={},n=m&&m.length?m:["width","height","top","left"];c.each(n||["width","height","top","left"],function(r,t){var s=(q[t]||0)+(j[t]||0);if(s&&s>=0){o[t]=s||null}});if(/relative/.test(p.css("position"))&&c.browser.opera){e._revertToRelativePosition=true;p.css({position:"absolute",top:"auto",left:"auto"})}p.css(o)})};if(typeof(i.alsoResize)=="object"&&!i.alsoResize.nodeType){c.each(i.alsoResize,function(l,m){d(l,m)})}else{d(i.alsoResize)}},stop:function(e,f){var d=c(this).data("resizable");if(d._revertToRelativePosition&&c.browser.opera){d._revertToRelativePosition=false;el.css({position:"relative"})}c(this).removeData("resizable-alsoresize-start")}});c.ui.plugin.add("resizable","animate",{stop:function(h,m){var n=c(this).data("resizable"),i=n.options;var g=n._proportionallyResizeElements,d=g.length&&(/textarea/i).test(g[0].nodeName),e=d&&c.ui.hasScroll(g[0],"left")?0:n.sizeDiff.height,k=d?0:n.sizeDiff.width;var f={width:(n.size.width-k),height:(n.size.height-e)},j=(parseInt(n.element.css("left"),10)+(n.position.left-n.originalPosition.left))||null,l=(parseInt(n.element.css("top"),10)+(n.position.top-n.originalPosition.top))||null;n.element.animate(c.extend(f,l&&j?{top:l,left:j}:{}),{duration:i.animateDuration,easing:i.animateEasing,step:function(){var o={width:parseInt(n.element.css("width"),10),height:parseInt(n.element.css("height"),10),top:parseInt(n.element.css("top"),10),left:parseInt(n.element.css("left"),10)};if(g&&g.length){c(g[0]).css({width:o.width,height:o.height})}n._updateCache(o);n._propagate("resize",h)}})}});c.ui.plugin.add("resizable","containment",{start:function(e,q){var s=c(this).data("resizable"),i=s.options,k=s.element;var f=i.containment,j=(f instanceof c)?f.get(0):(/parent/.test(f))?k.parent().get(0):f;if(!j){return}s.containerElement=c(j);if(/document/.test(f)||f==document){s.containerOffset={left:0,top:0};s.containerPosition={left:0,top:0};s.parentData={element:c(document),left:0,top:0,width:c(document).width(),height:c(document).height()||document.body.parentNode.scrollHeight}}else{var m=c(j),h=[];c(["Top","Right","Left","Bottom"]).each(function(p,o){h[p]=b(m.css("padding"+o))});s.containerOffset=m.offset();s.containerPosition=m.position();s.containerSize={height:(m.innerHeight()-h[3]),width:(m.innerWidth()-h[1])};var n=s.containerOffset,d=s.containerSize.height,l=s.containerSize.width,g=(c.ui.hasScroll(j,"left")?j.scrollWidth:l),r=(c.ui.hasScroll(j)?j.scrollHeight:d);s.parentData={element:j,left:n.left,top:n.top,width:g,height:r}}},resize:function(f,p){var s=c(this).data("resizable"),h=s.options,e=s.containerSize,n=s.containerOffset,l=s.size,m=s.position,q=s._aspectRatio||f.shiftKey,d={top:0,left:0},g=s.containerElement;if(g[0]!=document&&(/static/).test(g.css("position"))){d=n}if(m.left<(s._helper?n.left:0)){s.size.width=s.size.width+(s._helper?(s.position.left-n.left):(s.position.left-d.left));if(q){s.size.height=s.size.width/h.aspectRatio}s.position.left=h.helper?n.left:0}if(m.top<(s._helper?n.top:0)){s.size.height=s.size.height+(s._helper?(s.position.top-n.top):s.position.top);if(q){s.size.width=s.size.height*h.aspectRatio}s.position.top=s._helper?n.top:0}s.offset.left=s.parentData.left+s.position.left;s.offset.top=s.parentData.top+s.position.top;var k=Math.abs((s._helper?s.offset.left-d.left:(s.offset.left-d.left))+s.sizeDiff.width),r=Math.abs((s._helper?s.offset.top-d.top:(s.offset.top-n.top))+s.sizeDiff.height);var j=s.containerElement.get(0)==s.element.parent().get(0),i=/relative|absolute/.test(s.containerElement.css("position"));if(j&&i){k-=s.parentData.left}if(k+s.size.width>=s.parentData.width){s.size.width=s.parentData.width-k;if(q){s.size.height=s.size.width/s.aspectRatio}}if(r+s.size.height>=s.parentData.height){s.size.height=s.parentData.height-r;if(q){s.size.width=s.size.height*s.aspectRatio}}},stop:function(e,m){var p=c(this).data("resizable"),f=p.options,k=p.position,l=p.containerOffset,d=p.containerPosition,g=p.containerElement;var i=c(p.helper),q=i.offset(),n=i.outerWidth()-p.sizeDiff.width,j=i.outerHeight()-p.sizeDiff.height;if(p._helper&&!f.animate&&(/relative/).test(g.css("position"))){c(this).css({left:q.left-d.left-l.left,width:n,height:j})}if(p._helper&&!f.animate&&(/static/).test(g.css("position"))){c(this).css({left:q.left-d.left-l.left,width:n,height:j})}}});c.ui.plugin.add("resizable","ghost",{start:function(f,g){var d=c(this).data("resizable"),h=d.options,e=d.size;d.ghost=d.originalElement.clone();d.ghost.css({opacity:0.25,display:"block",position:"relative",height:e.height,width:e.width,margin:0,left:0,top:0}).addClass("ui-resizable-ghost").addClass(typeof h.ghost=="string"?h.ghost:"");d.ghost.appendTo(d.helper)},resize:function(e,f){var d=c(this).data("resizable"),g=d.options;if(d.ghost){d.ghost.css({position:"relative",height:d.size.height,width:d.size.width})}},stop:function(e,f){var d=c(this).data("resizable"),g=d.options;if(d.ghost&&d.helper){d.helper.get(0).removeChild(d.ghost.get(0))}}});c.ui.plugin.add("resizable","grid",{resize:function(d,l){var n=c(this).data("resizable"),g=n.options,j=n.size,h=n.originalSize,i=n.originalPosition,m=n.axis,k=g._aspectRatio||d.shiftKey;g.grid=typeof g.grid=="number"?[g.grid,g.grid]:g.grid;var f=Math.round((j.width-h.width)/(g.grid[0]||1))*(g.grid[0]||1),e=Math.round((j.height-h.height)/(g.grid[1]||1))*(g.grid[1]||1);if(/^(se|s|e)$/.test(m)){n.size.width=h.width+f;n.size.height=h.height+e}else{if(/^(ne)$/.test(m)){n.size.width=h.width+f;n.size.height=h.height+e;n.position.top=i.top-e}else{if(/^(sw)$/.test(m)){n.size.width=h.width+f;n.size.height=h.height+e;n.position.left=i.left-f}else{n.size.width=h.width+f;n.size.height=h.height+e;n.position.top=i.top-e;n.position.left=i.left-f}}}}});var b=function(d){return parseInt(d,10)||0};var a=function(d){return !isNaN(parseInt(d,10))}})(jQuery);;/* - * jQuery UI Selectable 1.7.2 - * - * Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT (MIT-LICENSE.txt) - * and GPL (GPL-LICENSE.txt) licenses. - * - * http://docs.jquery.com/UI/Selectables - * - * Depends: - * ui.core.js - */ -(function(a){a.widget("ui.selectable",a.extend({},a.ui.mouse,{_init:function(){var b=this;this.element.addClass("ui-selectable");this.dragged=false;var c;this.refresh=function(){c=a(b.options.filter,b.element[0]);c.each(function(){var d=a(this);var e=d.offset();a.data(this,"selectable-item",{element:this,$element:d,left:e.left,top:e.top,right:e.left+d.outerWidth(),bottom:e.top+d.outerHeight(),startselected:false,selected:d.hasClass("ui-selected"),selecting:d.hasClass("ui-selecting"),unselecting:d.hasClass("ui-unselecting")})})};this.refresh();this.selectees=c.addClass("ui-selectee");this._mouseInit();this.helper=a(document.createElement("div")).css({border:"1px dotted black"}).addClass("ui-selectable-helper")},destroy:function(){this.element.removeClass("ui-selectable ui-selectable-disabled").removeData("selectable").unbind(".selectable");this._mouseDestroy()},_mouseStart:function(d){var b=this;this.opos=[d.pageX,d.pageY];if(this.options.disabled){return}var c=this.options;this.selectees=a(c.filter,this.element[0]);this._trigger("start",d);a(c.appendTo).append(this.helper);this.helper.css({"z-index":100,position:"absolute",left:d.clientX,top:d.clientY,width:0,height:0});if(c.autoRefresh){this.refresh()}this.selectees.filter(".ui-selected").each(function(){var e=a.data(this,"selectable-item");e.startselected=true;if(!d.metaKey){e.$element.removeClass("ui-selected");e.selected=false;e.$element.addClass("ui-unselecting");e.unselecting=true;b._trigger("unselecting",d,{unselecting:e.element})}});a(d.target).parents().andSelf().each(function(){var e=a.data(this,"selectable-item");if(e){e.$element.removeClass("ui-unselecting").addClass("ui-selecting");e.unselecting=false;e.selecting=true;e.selected=true;b._trigger("selecting",d,{selecting:e.element});return false}})},_mouseDrag:function(i){var c=this;this.dragged=true;if(this.options.disabled){return}var e=this.options;var d=this.opos[0],h=this.opos[1],b=i.pageX,g=i.pageY;if(d>b){var f=b;b=d;d=f}if(h>g){var f=g;g=h;h=f}this.helper.css({left:d,top:h,width:b-d,height:g-h});this.selectees.each(function(){var j=a.data(this,"selectable-item");if(!j||j.element==c.element[0]){return}var k=false;if(e.tolerance=="touch"){k=(!(j.left>b||j.rightg||j.bottomd&&j.righth&&j.bottom=0&&this.anchors[d.selected])||d.selected<0)?d.selected:0;d.disabled=a.unique(d.disabled.concat(a.map(this.lis.filter(".ui-state-disabled"),function(q,o){return p.lis.index(q)}))).sort();if(a.inArray(d.selected,d.disabled)!=-1){d.disabled.splice(a.inArray(d.selected,d.disabled),1)}this.panels.addClass("ui-tabs-hide");this.lis.removeClass("ui-tabs-selected ui-state-active");if(d.selected>=0&&this.anchors.length){this.panels.eq(d.selected).removeClass("ui-tabs-hide");this.lis.eq(d.selected).addClass("ui-tabs-selected ui-state-active");p.element.queue("tabs",function(){p._trigger("show",null,p._ui(p.anchors[d.selected],p.panels[d.selected]))});this.load(d.selected)}a(window).bind("unload",function(){p.lis.add(p.anchors).unbind(".tabs");p.lis=p.anchors=p.panels=null})}else{d.selected=this.lis.index(this.lis.filter(".ui-tabs-selected"))}this.element[d.collapsible?"addClass":"removeClass"]("ui-tabs-collapsible");if(d.cookie){this._cookie(d.selected,d.cookie)}for(var g=0,m;(m=this.lis[g]);g++){a(m)[a.inArray(g,d.disabled)!=-1&&!a(m).hasClass("ui-tabs-selected")?"addClass":"removeClass"]("ui-state-disabled")}if(d.cache===false){this.anchors.removeData("cache.tabs")}this.lis.add(this.anchors).unbind(".tabs");if(d.event!="mouseover"){var f=function(o,i){if(i.is(":not(.ui-state-disabled)")){i.addClass("ui-state-"+o)}};var j=function(o,i){i.removeClass("ui-state-"+o)};this.lis.bind("mouseover.tabs",function(){f("hover",a(this))});this.lis.bind("mouseout.tabs",function(){j("hover",a(this))});this.anchors.bind("focus.tabs",function(){f("focus",a(this).closest("li"))});this.anchors.bind("blur.tabs",function(){j("focus",a(this).closest("li"))})}var b,h;if(d.fx){if(a.isArray(d.fx)){b=d.fx[0];h=d.fx[1]}else{b=h=d.fx}}function e(i,o){i.css({display:""});if(a.browser.msie&&o.opacity){i[0].style.removeAttribute("filter")}}var k=h?function(i,o){a(i).closest("li").removeClass("ui-state-default").addClass("ui-tabs-selected ui-state-active");o.hide().removeClass("ui-tabs-hide").animate(h,h.duration||"normal",function(){e(o,h);p._trigger("show",null,p._ui(i,o[0]))})}:function(i,o){a(i).closest("li").removeClass("ui-state-default").addClass("ui-tabs-selected ui-state-active");o.removeClass("ui-tabs-hide");p._trigger("show",null,p._ui(i,o[0]))};var l=b?function(o,i){i.animate(b,b.duration||"normal",function(){p.lis.removeClass("ui-tabs-selected ui-state-active").addClass("ui-state-default");i.addClass("ui-tabs-hide");e(i,b);p.element.dequeue("tabs")})}:function(o,i,q){p.lis.removeClass("ui-tabs-selected ui-state-active").addClass("ui-state-default");i.addClass("ui-tabs-hide");p.element.dequeue("tabs")};this.anchors.bind(d.event+".tabs",function(){var o=this,r=a(this).closest("li"),i=p.panels.filter(":not(.ui-tabs-hide)"),q=a(p._sanitizeSelector(this.hash));if((r.hasClass("ui-tabs-selected")&&!d.collapsible)||r.hasClass("ui-state-disabled")||r.hasClass("ui-state-processing")||p._trigger("select",null,p._ui(this,q[0]))===false){this.blur();return false}d.selected=p.anchors.index(this);p.abort();if(d.collapsible){if(r.hasClass("ui-tabs-selected")){d.selected=-1;if(d.cookie){p._cookie(d.selected,d.cookie)}p.element.queue("tabs",function(){l(o,i)}).dequeue("tabs");this.blur();return false}else{if(!i.length){if(d.cookie){p._cookie(d.selected,d.cookie)}p.element.queue("tabs",function(){k(o,q)});p.load(p.anchors.index(this));this.blur();return false}}}if(d.cookie){p._cookie(d.selected,d.cookie)}if(q.length){if(i.length){p.element.queue("tabs",function(){l(o,i)})}p.element.queue("tabs",function(){k(o,q)});p.load(p.anchors.index(this))}else{throw"jQuery UI Tabs: Mismatching fragment identifier."}if(a.browser.msie){this.blur()}});this.anchors.bind("click.tabs",function(){return false})},destroy:function(){var b=this.options;this.abort();this.element.unbind(".tabs").removeClass("ui-tabs ui-widget ui-widget-content ui-corner-all ui-tabs-collapsible").removeData("tabs");this.list.removeClass("ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all");this.anchors.each(function(){var c=a.data(this,"href.tabs");if(c){this.href=c}var d=a(this).unbind(".tabs");a.each(["href","load","cache"],function(e,f){d.removeData(f+".tabs")})});this.lis.unbind(".tabs").add(this.panels).each(function(){if(a.data(this,"destroy.tabs")){a(this).remove()}else{a(this).removeClass(["ui-state-default","ui-corner-top","ui-tabs-selected","ui-state-active","ui-state-hover","ui-state-focus","ui-state-disabled","ui-tabs-panel","ui-widget-content","ui-corner-bottom","ui-tabs-hide"].join(" "))}});if(b.cookie){this._cookie(null,b.cookie)}},add:function(e,d,c){if(c===undefined){c=this.anchors.length}var b=this,g=this.options,i=a(g.tabTemplate.replace(/#\{href\}/g,e).replace(/#\{label\}/g,d)),h=!e.indexOf("#")?e.replace("#",""):this._tabId(a("a",i)[0]);i.addClass("ui-state-default ui-corner-top").data("destroy.tabs",true);var f=a("#"+h);if(!f.length){f=a(g.panelTemplate).attr("id",h).data("destroy.tabs",true)}f.addClass("ui-tabs-panel ui-widget-content ui-corner-bottom ui-tabs-hide");if(c>=this.lis.length){i.appendTo(this.list);f.appendTo(this.list[0].parentNode)}else{i.insertBefore(this.lis[c]);f.insertBefore(this.panels[c])}g.disabled=a.map(g.disabled,function(k,j){return k>=c?++k:k});this._tabify();if(this.anchors.length==1){i.addClass("ui-tabs-selected ui-state-active");f.removeClass("ui-tabs-hide");this.element.queue("tabs",function(){b._trigger("show",null,b._ui(b.anchors[0],b.panels[0]))});this.load(0)}this._trigger("add",null,this._ui(this.anchors[c],this.panels[c]))},remove:function(b){var d=this.options,e=this.lis.eq(b).remove(),c=this.panels.eq(b).remove();if(e.hasClass("ui-tabs-selected")&&this.anchors.length>1){this.select(b+(b+1=b?--g:g});this._tabify();this._trigger("remove",null,this._ui(e.find("a")[0],c[0]))},enable:function(b){var c=this.options;if(a.inArray(b,c.disabled)==-1){return}this.lis.eq(b).removeClass("ui-state-disabled");c.disabled=a.grep(c.disabled,function(e,d){return e!=b});this._trigger("enable",null,this._ui(this.anchors[b],this.panels[b]))},disable:function(c){var b=this,d=this.options;if(c!=d.selected){this.lis.eq(c).addClass("ui-state-disabled");d.disabled.push(c);d.disabled.sort();this._trigger("disable",null,this._ui(this.anchors[c],this.panels[c]))}},select:function(b){if(typeof b=="string"){b=this.anchors.index(this.anchors.filter("[href$="+b+"]"))}else{if(b===null){b=-1}}if(b==-1&&this.options.collapsible){b=this.options.selected}this.anchors.eq(b).trigger(this.options.event+".tabs")},load:function(e){var c=this,g=this.options,b=this.anchors.eq(e)[0],d=a.data(b,"load.tabs");this.abort();if(!d||this.element.queue("tabs").length!==0&&a.data(b,"cache.tabs")){this.element.dequeue("tabs");return}this.lis.eq(e).addClass("ui-state-processing");if(g.spinner){var f=a("span",b);f.data("label.tabs",f.html()).html(g.spinner)}this.xhr=a.ajax(a.extend({},g.ajaxOptions,{url:d,success:function(i,h){a(c._sanitizeSelector(b.hash)).html(i);c._cleanup();if(g.cache){a.data(b,"cache.tabs",true)}c._trigger("load",null,c._ui(c.anchors[e],c.panels[e]));try{g.ajaxOptions.success(i,h)}catch(j){}c.element.dequeue("tabs")}}))},abort:function(){this.element.queue([]);this.panels.stop(false,true);if(this.xhr){this.xhr.abort();delete this.xhr}this._cleanup()},url:function(c,b){this.anchors.eq(c).removeData("cache.tabs").data("load.tabs",b)},length:function(){return this.anchors.length}});a.extend(a.ui.tabs,{version:"1.7.2",getter:"length",defaults:{ajaxOptions:null,cache:false,cookie:null,collapsible:false,disabled:[],event:"click",fx:null,idPrefix:"ui-tabs-",panelTemplate:"
                          ",spinner:"Loading…",tabTemplate:'
                        • #{label}
                        • '}});a.extend(a.ui.tabs.prototype,{rotation:null,rotate:function(d,f){var b=this,g=this.options;var c=b._rotate||(b._rotate=function(h){clearTimeout(b.rotation);b.rotation=setTimeout(function(){var i=g.selected;b.select(++i
                          ')}$.extend(Datepicker.prototype,{markerClassName:"hasDatepicker",log:function(){if(this.debug){console.log.apply("",arguments)}},setDefaults:function(settings){extendRemove(this._defaults,settings||{});return this},_attachDatepicker:function(target,settings){var inlineSettings=null;for(var attrName in this._defaults){var attrValue=target.getAttribute("date:"+attrName);if(attrValue){inlineSettings=inlineSettings||{};try{inlineSettings[attrName]=eval(attrValue)}catch(err){inlineSettings[attrName]=attrValue}}}var nodeName=target.nodeName.toLowerCase();var inline=(nodeName=="div"||nodeName=="span");if(!target.id){target.id="dp"+(++this.uuid)}var inst=this._newInst($(target),inline);inst.settings=$.extend({},settings||{},inlineSettings||{});if(nodeName=="input"){this._connectDatepicker(target,inst)}else{if(inline){this._inlineDatepicker(target,inst)}}},_newInst:function(target,inline){var id=target[0].id.replace(/([:\[\]\.])/g,"\\\\$1");return{id:id,input:target,selectedDay:0,selectedMonth:0,selectedYear:0,drawMonth:0,drawYear:0,inline:inline,dpDiv:(!inline?this.dpDiv:$('
                          '))}},_connectDatepicker:function(target,inst){var input=$(target);inst.append=$([]);inst.trigger=$([]);if(input.hasClass(this.markerClassName)){return}var appendText=this._get(inst,"appendText");var isRTL=this._get(inst,"isRTL");if(appendText){inst.append=$(''+appendText+"");input[isRTL?"before":"after"](inst.append)}var showOn=this._get(inst,"showOn");if(showOn=="focus"||showOn=="both"){input.focus(this._showDatepicker)}if(showOn=="button"||showOn=="both"){var buttonText=this._get(inst,"buttonText");var buttonImage=this._get(inst,"buttonImage");inst.trigger=$(this._get(inst,"buttonImageOnly")?$("").addClass(this._triggerClass).attr({src:buttonImage,alt:buttonText,title:buttonText}):$('').addClass(this._triggerClass).html(buttonImage==""?buttonText:$("").attr({src:buttonImage,alt:buttonText,title:buttonText})));input[isRTL?"before":"after"](inst.trigger);inst.trigger.click(function(){if($.datepicker._datepickerShowing&&$.datepicker._lastInput==target){$.datepicker._hideDatepicker()}else{$.datepicker._showDatepicker(target)}return false})}input.addClass(this.markerClassName).keydown(this._doKeyDown).keypress(this._doKeyPress).bind("setData.datepicker",function(event,key,value){inst.settings[key]=value}).bind("getData.datepicker",function(event,key){return this._get(inst,key)});$.data(target,PROP_NAME,inst)},_inlineDatepicker:function(target,inst){var divSpan=$(target);if(divSpan.hasClass(this.markerClassName)){return}divSpan.addClass(this.markerClassName).append(inst.dpDiv).bind("setData.datepicker",function(event,key,value){inst.settings[key]=value}).bind("getData.datepicker",function(event,key){return this._get(inst,key)});$.data(target,PROP_NAME,inst);this._setDate(inst,this._getDefaultDate(inst));this._updateDatepicker(inst);this._updateAlternate(inst)},_dialogDatepicker:function(input,dateText,onSelect,settings,pos){var inst=this._dialogInst;if(!inst){var id="dp"+(++this.uuid);this._dialogInput=$('');this._dialogInput.keydown(this._doKeyDown);$("body").append(this._dialogInput);inst=this._dialogInst=this._newInst(this._dialogInput,false);inst.settings={};$.data(this._dialogInput[0],PROP_NAME,inst)}extendRemove(inst.settings,settings||{});this._dialogInput.val(dateText);this._pos=(pos?(pos.length?pos:[pos.pageX,pos.pageY]):null);if(!this._pos){var browserWidth=window.innerWidth||document.documentElement.clientWidth||document.body.clientWidth;var browserHeight=window.innerHeight||document.documentElement.clientHeight||document.body.clientHeight;var scrollX=document.documentElement.scrollLeft||document.body.scrollLeft;var scrollY=document.documentElement.scrollTop||document.body.scrollTop;this._pos=[(browserWidth/2)-100+scrollX,(browserHeight/2)-150+scrollY]}this._dialogInput.css("left",this._pos[0]+"px").css("top",this._pos[1]+"px");inst.settings.onSelect=onSelect;this._inDialog=true;this.dpDiv.addClass(this._dialogClass);this._showDatepicker(this._dialogInput[0]);if($.blockUI){$.blockUI(this.dpDiv)}$.data(this._dialogInput[0],PROP_NAME,inst);return this},_destroyDatepicker:function(target){var $target=$(target);var inst=$.data(target,PROP_NAME);if(!$target.hasClass(this.markerClassName)){return}var nodeName=target.nodeName.toLowerCase();$.removeData(target,PROP_NAME);if(nodeName=="input"){inst.append.remove();inst.trigger.remove();$target.removeClass(this.markerClassName).unbind("focus",this._showDatepicker).unbind("keydown",this._doKeyDown).unbind("keypress",this._doKeyPress)}else{if(nodeName=="div"||nodeName=="span"){$target.removeClass(this.markerClassName).empty()}}},_enableDatepicker:function(target){var $target=$(target);var inst=$.data(target,PROP_NAME);if(!$target.hasClass(this.markerClassName)){return}var nodeName=target.nodeName.toLowerCase();if(nodeName=="input"){target.disabled=false;inst.trigger.filter("button").each(function(){this.disabled=false}).end().filter("img").css({opacity:"1.0",cursor:""})}else{if(nodeName=="div"||nodeName=="span"){var inline=$target.children("."+this._inlineClass);inline.children().removeClass("ui-state-disabled")}}this._disabledInputs=$.map(this._disabledInputs,function(value){return(value==target?null:value)})},_disableDatepicker:function(target){var $target=$(target);var inst=$.data(target,PROP_NAME);if(!$target.hasClass(this.markerClassName)){return}var nodeName=target.nodeName.toLowerCase();if(nodeName=="input"){target.disabled=true;inst.trigger.filter("button").each(function(){this.disabled=true}).end().filter("img").css({opacity:"0.5",cursor:"default"})}else{if(nodeName=="div"||nodeName=="span"){var inline=$target.children("."+this._inlineClass);inline.children().addClass("ui-state-disabled")}}this._disabledInputs=$.map(this._disabledInputs,function(value){return(value==target?null:value)});this._disabledInputs[this._disabledInputs.length]=target},_isDisabledDatepicker:function(target){if(!target){return false}for(var i=0;i-1)}},_showDatepicker:function(input){input=input.target||input;if(input.nodeName.toLowerCase()!="input"){input=$("input",input.parentNode)[0]}if($.datepicker._isDisabledDatepicker(input)||$.datepicker._lastInput==input){return}var inst=$.datepicker._getInst(input);var beforeShow=$.datepicker._get(inst,"beforeShow");extendRemove(inst.settings,(beforeShow?beforeShow.apply(input,[input,inst]):{}));$.datepicker._hideDatepicker(null,"");$.datepicker._lastInput=input;$.datepicker._setDateFromField(inst);if($.datepicker._inDialog){input.value=""}if(!$.datepicker._pos){$.datepicker._pos=$.datepicker._findPos(input);$.datepicker._pos[1]+=input.offsetHeight}var isFixed=false;$(input).parents().each(function(){isFixed|=$(this).css("position")=="fixed";return !isFixed});if(isFixed&&$.browser.opera){$.datepicker._pos[0]-=document.documentElement.scrollLeft;$.datepicker._pos[1]-=document.documentElement.scrollTop}var offset={left:$.datepicker._pos[0],top:$.datepicker._pos[1]};$.datepicker._pos=null;inst.rangeStart=null;inst.dpDiv.css({position:"absolute",display:"block",top:"-1000px"});$.datepicker._updateDatepicker(inst);offset=$.datepicker._checkOffset(inst,offset,isFixed);inst.dpDiv.css({position:($.datepicker._inDialog&&$.blockUI?"static":(isFixed?"fixed":"absolute")),display:"none",left:offset.left+"px",top:offset.top+"px"});if(!inst.inline){var showAnim=$.datepicker._get(inst,"showAnim")||"show";var duration=$.datepicker._get(inst,"duration");var postProcess=function(){$.datepicker._datepickerShowing=true;if($.browser.msie&&parseInt($.browser.version,10)<7){$("iframe.ui-datepicker-cover").css({width:inst.dpDiv.width()+4,height:inst.dpDiv.height()+4})}};if($.effects&&$.effects[showAnim]){inst.dpDiv.show(showAnim,$.datepicker._get(inst,"showOptions"),duration,postProcess)}else{inst.dpDiv[showAnim](duration,postProcess)}if(duration==""){postProcess()}if(inst.input[0].type!="hidden"){inst.input[0].focus()}$.datepicker._curInst=inst}},_updateDatepicker:function(inst){var dims={width:inst.dpDiv.width()+4,height:inst.dpDiv.height()+4};var self=this;inst.dpDiv.empty().append(this._generateHTML(inst)).find("iframe.ui-datepicker-cover").css({width:dims.width,height:dims.height}).end().find("button, .ui-datepicker-prev, .ui-datepicker-next, .ui-datepicker-calendar td a").bind("mouseout",function(){$(this).removeClass("ui-state-hover");if(this.className.indexOf("ui-datepicker-prev")!=-1){$(this).removeClass("ui-datepicker-prev-hover")}if(this.className.indexOf("ui-datepicker-next")!=-1){$(this).removeClass("ui-datepicker-next-hover")}}).bind("mouseover",function(){if(!self._isDisabledDatepicker(inst.inline?inst.dpDiv.parent()[0]:inst.input[0])){$(this).parents(".ui-datepicker-calendar").find("a").removeClass("ui-state-hover");$(this).addClass("ui-state-hover");if(this.className.indexOf("ui-datepicker-prev")!=-1){$(this).addClass("ui-datepicker-prev-hover")}if(this.className.indexOf("ui-datepicker-next")!=-1){$(this).addClass("ui-datepicker-next-hover")}}}).end().find("."+this._dayOverClass+" a").trigger("mouseover").end();var numMonths=this._getNumberOfMonths(inst);var cols=numMonths[1];var width=17;if(cols>1){inst.dpDiv.addClass("ui-datepicker-multi-"+cols).css("width",(width*cols)+"em")}else{inst.dpDiv.removeClass("ui-datepicker-multi-2 ui-datepicker-multi-3 ui-datepicker-multi-4").width("")}inst.dpDiv[(numMonths[0]!=1||numMonths[1]!=1?"add":"remove")+"Class"]("ui-datepicker-multi");inst.dpDiv[(this._get(inst,"isRTL")?"add":"remove")+"Class"]("ui-datepicker-rtl");if(inst.input&&inst.input[0].type!="hidden"&&inst==$.datepicker._curInst){$(inst.input[0]).focus()}},_checkOffset:function(inst,offset,isFixed){var dpWidth=inst.dpDiv.outerWidth();var dpHeight=inst.dpDiv.outerHeight();var inputWidth=inst.input?inst.input.outerWidth():0;var inputHeight=inst.input?inst.input.outerHeight():0;var viewWidth=(window.innerWidth||document.documentElement.clientWidth||document.body.clientWidth)+$(document).scrollLeft();var viewHeight=(window.innerHeight||document.documentElement.clientHeight||document.body.clientHeight)+$(document).scrollTop();offset.left-=(this._get(inst,"isRTL")?(dpWidth-inputWidth):0);offset.left-=(isFixed&&offset.left==inst.input.offset().left)?$(document).scrollLeft():0;offset.top-=(isFixed&&offset.top==(inst.input.offset().top+inputHeight))?$(document).scrollTop():0;offset.left-=(offset.left+dpWidth>viewWidth&&viewWidth>dpWidth)?Math.abs(offset.left+dpWidth-viewWidth):0;offset.top-=(offset.top+dpHeight>viewHeight&&viewHeight>dpHeight)?Math.abs(offset.top+dpHeight+inputHeight*2-viewHeight):0;return offset},_findPos:function(obj){while(obj&&(obj.type=="hidden"||obj.nodeType!=1)){obj=obj.nextSibling}var position=$(obj).offset();return[position.left,position.top]},_hideDatepicker:function(input,duration){var inst=this._curInst;if(!inst||(input&&inst!=$.data(input,PROP_NAME))){return}if(inst.stayOpen){this._selectDate("#"+inst.id,this._formatDate(inst,inst.currentDay,inst.currentMonth,inst.currentYear))}inst.stayOpen=false;if(this._datepickerShowing){duration=(duration!=null?duration:this._get(inst,"duration"));var showAnim=this._get(inst,"showAnim");var postProcess=function(){$.datepicker._tidyDialog(inst)};if(duration!=""&&$.effects&&$.effects[showAnim]){inst.dpDiv.hide(showAnim,$.datepicker._get(inst,"showOptions"),duration,postProcess)}else{inst.dpDiv[(duration==""?"hide":(showAnim=="slideDown"?"slideUp":(showAnim=="fadeIn"?"fadeOut":"hide")))](duration,postProcess)}if(duration==""){this._tidyDialog(inst)}var onClose=this._get(inst,"onClose");if(onClose){onClose.apply((inst.input?inst.input[0]:null),[(inst.input?inst.input.val():""),inst])}this._datepickerShowing=false;this._lastInput=null;if(this._inDialog){this._dialogInput.css({position:"absolute",left:"0",top:"-100px"});if($.blockUI){$.unblockUI();$("body").append(this.dpDiv)}}this._inDialog=false}this._curInst=null},_tidyDialog:function(inst){inst.dpDiv.removeClass(this._dialogClass).unbind(".ui-datepicker-calendar")},_checkExternalClick:function(event){if(!$.datepicker._curInst){return}var $target=$(event.target);if(($target.parents("#"+$.datepicker._mainDivId).length==0)&&!$target.hasClass($.datepicker.markerClassName)&&!$target.hasClass($.datepicker._triggerClass)&&$.datepicker._datepickerShowing&&!($.datepicker._inDialog&&$.blockUI)){$.datepicker._hideDatepicker(null,"")}},_adjustDate:function(id,offset,period){var target=$(id);var inst=this._getInst(target[0]);if(this._isDisabledDatepicker(target[0])){return}this._adjustInstDate(inst,offset+(period=="M"?this._get(inst,"showCurrentAtPos"):0),period);this._updateDatepicker(inst)},_gotoToday:function(id){var target=$(id);var inst=this._getInst(target[0]);if(this._get(inst,"gotoCurrent")&&inst.currentDay){inst.selectedDay=inst.currentDay;inst.drawMonth=inst.selectedMonth=inst.currentMonth;inst.drawYear=inst.selectedYear=inst.currentYear}else{var date=new Date();inst.selectedDay=date.getDate();inst.drawMonth=inst.selectedMonth=date.getMonth();inst.drawYear=inst.selectedYear=date.getFullYear()}this._notifyChange(inst);this._adjustDate(target)},_selectMonthYear:function(id,select,period){var target=$(id);var inst=this._getInst(target[0]);inst._selectingMonthYear=false;inst["selected"+(period=="M"?"Month":"Year")]=inst["draw"+(period=="M"?"Month":"Year")]=parseInt(select.options[select.selectedIndex].value,10);this._notifyChange(inst);this._adjustDate(target)},_clickMonthYear:function(id){var target=$(id);var inst=this._getInst(target[0]);if(inst.input&&inst._selectingMonthYear&&!$.browser.msie){inst.input[0].focus()}inst._selectingMonthYear=!inst._selectingMonthYear},_selectDay:function(id,month,year,td){var target=$(id);if($(td).hasClass(this._unselectableClass)||this._isDisabledDatepicker(target[0])){return}var inst=this._getInst(target[0]);inst.selectedDay=inst.currentDay=$("a",td).html();inst.selectedMonth=inst.currentMonth=month;inst.selectedYear=inst.currentYear=year;if(inst.stayOpen){inst.endDay=inst.endMonth=inst.endYear=null}this._selectDate(id,this._formatDate(inst,inst.currentDay,inst.currentMonth,inst.currentYear));if(inst.stayOpen){inst.rangeStart=this._daylightSavingAdjust(new Date(inst.currentYear,inst.currentMonth,inst.currentDay));this._updateDatepicker(inst)}},_clearDate:function(id){var target=$(id);var inst=this._getInst(target[0]);inst.stayOpen=false;inst.endDay=inst.endMonth=inst.endYear=inst.rangeStart=null;this._selectDate(target,"")},_selectDate:function(id,dateStr){var target=$(id);var inst=this._getInst(target[0]);dateStr=(dateStr!=null?dateStr:this._formatDate(inst));if(inst.input){inst.input.val(dateStr)}this._updateAlternate(inst);var onSelect=this._get(inst,"onSelect");if(onSelect){onSelect.apply((inst.input?inst.input[0]:null),[dateStr,inst])}else{if(inst.input){inst.input.trigger("change")}}if(inst.inline){this._updateDatepicker(inst)}else{if(!inst.stayOpen){this._hideDatepicker(null,this._get(inst,"duration"));this._lastInput=inst.input[0];if(typeof(inst.input[0])!="object"){inst.input[0].focus()}this._lastInput=null}}},_updateAlternate:function(inst){var altField=this._get(inst,"altField");if(altField){var altFormat=this._get(inst,"altFormat")||this._get(inst,"dateFormat");var date=this._getDate(inst);dateStr=this.formatDate(altFormat,date,this._getFormatConfig(inst));$(altField).each(function(){$(this).val(dateStr)})}},noWeekends:function(date){var day=date.getDay();return[(day>0&&day<6),""]},iso8601Week:function(date){var checkDate=new Date(date.getFullYear(),date.getMonth(),date.getDate());var firstMon=new Date(checkDate.getFullYear(),1-1,4);var firstDay=firstMon.getDay()||7;firstMon.setDate(firstMon.getDate()+1-firstDay);if(firstDay<4&&checkDatenew Date(checkDate.getFullYear(),12-1,28)){firstDay=new Date(checkDate.getFullYear()+1,1-1,4).getDay()||7;if(firstDay>4&&(checkDate.getDay()||7)0&&iValue="0"&&value.charAt(iValue)<="9"){num=num*10+parseInt(value.charAt(iValue++),10);size--}if(size==origSize){throw"Missing number at position "+iValue}return num};var getName=function(match,shortNames,longNames){var names=(lookAhead(match)?longNames:shortNames);var size=0;for(var j=0;j0&&iValue-1){month=1;day=doy;do{var dim=this._getDaysInMonth(year,month-1);if(day<=dim){break}month++;day-=dim}while(true)}var date=this._daylightSavingAdjust(new Date(year,month-1,day));if(date.getFullYear()!=year||date.getMonth()+1!=month||date.getDate()!=day){throw"Invalid date"}return date},ATOM:"yy-mm-dd",COOKIE:"D, dd M yy",ISO_8601:"yy-mm-dd",RFC_822:"D, d M y",RFC_850:"DD, dd-M-y",RFC_1036:"D, d M y",RFC_1123:"D, d M yy",RFC_2822:"D, d M yy",RSS:"D, d M y",TIMESTAMP:"@",W3C:"yy-mm-dd",formatDate:function(format,date,settings){if(!date){return""}var dayNamesShort=(settings?settings.dayNamesShort:null)||this._defaults.dayNamesShort;var dayNames=(settings?settings.dayNames:null)||this._defaults.dayNames;var monthNamesShort=(settings?settings.monthNamesShort:null)||this._defaults.monthNamesShort;var monthNames=(settings?settings.monthNames:null)||this._defaults.monthNames;var lookAhead=function(match){var matches=(iFormat+1=0;m--){doy+=this._getDaysInMonth(date.getFullYear(),m)}output+=formatNumber("o",doy,3);break;case"m":output+=formatNumber("m",date.getMonth()+1,2);break;case"M":output+=formatName("M",date.getMonth(),monthNamesShort,monthNames);break;case"y":output+=(lookAhead("y")?date.getFullYear():(date.getYear()%100<10?"0":"")+date.getYear()%100);break;case"@":output+=date.getTime();break;case"'":if(lookAhead("'")){output+="'"}else{literal=true}break;default:output+=format.charAt(iFormat)}}}}return output},_possibleChars:function(format){var chars="";var literal=false;for(var iFormat=0;iFormatmaxDate?maxDate:date);return date},_determineDate:function(date,defaultDate){var offsetNumeric=function(offset){var date=new Date();date.setDate(date.getDate()+offset);return date};var offsetString=function(offset,getDaysInMonth){var date=new Date();var year=date.getFullYear();var month=date.getMonth();var day=date.getDate();var pattern=/([+-]?[0-9]+)\s*(d|D|w|W|m|M|y|Y)?/g;var matches=pattern.exec(offset);while(matches){switch(matches[2]||"d"){case"d":case"D":day+=parseInt(matches[1],10);break;case"w":case"W":day+=parseInt(matches[1],10)*7;break;case"m":case"M":month+=parseInt(matches[1],10);day=Math.min(day,getDaysInMonth(year,month));break;case"y":case"Y":year+=parseInt(matches[1],10);day=Math.min(day,getDaysInMonth(year,month));break}matches=pattern.exec(offset)}return new Date(year,month,day)};date=(date==null?defaultDate:(typeof date=="string"?offsetString(date,this._getDaysInMonth):(typeof date=="number"?(isNaN(date)?defaultDate:offsetNumeric(date)):date)));date=(date&&date.toString()=="Invalid Date"?defaultDate:date);if(date){date.setHours(0);date.setMinutes(0);date.setSeconds(0);date.setMilliseconds(0)}return this._daylightSavingAdjust(date)},_daylightSavingAdjust:function(date){if(!date){return null}date.setHours(date.getHours()>12?date.getHours()+2:0);return date},_setDate:function(inst,date,endDate){var clear=!(date);var origMonth=inst.selectedMonth;var origYear=inst.selectedYear;date=this._determineDate(date,new Date());inst.selectedDay=inst.currentDay=date.getDate();inst.drawMonth=inst.selectedMonth=inst.currentMonth=date.getMonth();inst.drawYear=inst.selectedYear=inst.currentYear=date.getFullYear();if(origMonth!=inst.selectedMonth||origYear!=inst.selectedYear){this._notifyChange(inst)}this._adjustInstDate(inst);if(inst.input){inst.input.val(clear?"":this._formatDate(inst))}},_getDate:function(inst){var startDate=(!inst.currentYear||(inst.input&&inst.input.val()=="")?null:this._daylightSavingAdjust(new Date(inst.currentYear,inst.currentMonth,inst.currentDay)));return startDate},_generateHTML:function(inst){var today=new Date();today=this._daylightSavingAdjust(new Date(today.getFullYear(),today.getMonth(),today.getDate()));var isRTL=this._get(inst,"isRTL");var showButtonPanel=this._get(inst,"showButtonPanel");var hideIfNoPrevNext=this._get(inst,"hideIfNoPrevNext");var navigationAsDateFormat=this._get(inst,"navigationAsDateFormat");var numMonths=this._getNumberOfMonths(inst);var showCurrentAtPos=this._get(inst,"showCurrentAtPos");var stepMonths=this._get(inst,"stepMonths");var stepBigMonths=this._get(inst,"stepBigMonths");var isMultiMonth=(numMonths[0]!=1||numMonths[1]!=1);var currentDate=this._daylightSavingAdjust((!inst.currentDay?new Date(9999,9,9):new Date(inst.currentYear,inst.currentMonth,inst.currentDay)));var minDate=this._getMinMaxDate(inst,"min",true);var maxDate=this._getMinMaxDate(inst,"max");var drawMonth=inst.drawMonth-showCurrentAtPos;var drawYear=inst.drawYear;if(drawMonth<0){drawMonth+=12;drawYear--}if(maxDate){var maxDraw=this._daylightSavingAdjust(new Date(maxDate.getFullYear(),maxDate.getMonth()-numMonths[1]+1,maxDate.getDate()));maxDraw=(minDate&&maxDrawmaxDraw){drawMonth--;if(drawMonth<0){drawMonth=11;drawYear--}}}inst.drawMonth=drawMonth;inst.drawYear=drawYear;var prevText=this._get(inst,"prevText");prevText=(!navigationAsDateFormat?prevText:this.formatDate(prevText,this._daylightSavingAdjust(new Date(drawYear,drawMonth-stepMonths,1)),this._getFormatConfig(inst)));var prev=(this._canAdjustMonth(inst,-1,drawYear,drawMonth)?''+prevText+"":(hideIfNoPrevNext?"":''+prevText+""));var nextText=this._get(inst,"nextText");nextText=(!navigationAsDateFormat?nextText:this.formatDate(nextText,this._daylightSavingAdjust(new Date(drawYear,drawMonth+stepMonths,1)),this._getFormatConfig(inst)));var next=(this._canAdjustMonth(inst,+1,drawYear,drawMonth)?''+nextText+"":(hideIfNoPrevNext?"":''+nextText+""));var currentText=this._get(inst,"currentText");var gotoDate=(this._get(inst,"gotoCurrent")&&inst.currentDay?currentDate:today);currentText=(!navigationAsDateFormat?currentText:this.formatDate(currentText,gotoDate,this._getFormatConfig(inst)));var controls=(!inst.inline?'":"");var buttonPanel=(showButtonPanel)?'
                          '+(isRTL?controls:"")+(this._isInRange(inst,gotoDate)?'":"")+(isRTL?"":controls)+"
                          ":"";var firstDay=parseInt(this._get(inst,"firstDay"),10);firstDay=(isNaN(firstDay)?0:firstDay);var dayNames=this._get(inst,"dayNames");var dayNamesShort=this._get(inst,"dayNamesShort");var dayNamesMin=this._get(inst,"dayNamesMin");var monthNames=this._get(inst,"monthNames");var monthNamesShort=this._get(inst,"monthNamesShort");var beforeShowDay=this._get(inst,"beforeShowDay");var showOtherMonths=this._get(inst,"showOtherMonths");var calculateWeek=this._get(inst,"calculateWeek")||this.iso8601Week;var endDate=inst.endDay?this._daylightSavingAdjust(new Date(inst.endYear,inst.endMonth,inst.endDay)):currentDate;var defaultDate=this._getDefaultDate(inst);var html="";for(var row=0;row'+(/all|left/.test(cornerClass)&&row==0?(isRTL?next:prev):"")+(/all|right/.test(cornerClass)&&row==0?(isRTL?prev:next):"")+this._generateMonthYearHeader(inst,drawMonth,drawYear,minDate,maxDate,selectedDate,row>0||col>0,monthNames,monthNamesShort)+'
                          ';var thead="";for(var dow=0;dow<7;dow++){var day=(dow+firstDay)%7;thead+="=5?' class="ui-datepicker-week-end"':"")+'>'+dayNamesMin[day]+""}calender+=thead+"";var daysInMonth=this._getDaysInMonth(drawYear,drawMonth);if(drawYear==inst.selectedYear&&drawMonth==inst.selectedMonth){inst.selectedDay=Math.min(inst.selectedDay,daysInMonth)}var leadDays=(this._getFirstDayOfMonth(drawYear,drawMonth)-firstDay+7)%7;var numRows=(isMultiMonth?6:Math.ceil((leadDays+daysInMonth)/7));var printDate=this._daylightSavingAdjust(new Date(drawYear,drawMonth,1-leadDays));for(var dRow=0;dRow";var tbody="";for(var dow=0;dow<7;dow++){var daySettings=(beforeShowDay?beforeShowDay.apply((inst.input?inst.input[0]:null),[printDate]):[true,""]);var otherMonth=(printDate.getMonth()!=drawMonth);var unselectable=otherMonth||!daySettings[0]||(minDate&&printDatemaxDate);tbody+='";printDate.setDate(printDate.getDate()+1);printDate=this._daylightSavingAdjust(printDate)}calender+=tbody+""}drawMonth++;if(drawMonth>11){drawMonth=0;drawYear++}calender+="
                          =currentDate.getTime()&&printDate.getTime()<=endDate.getTime()?" "+this._currentClass:"")+(printDate.getTime()==today.getTime()?" ui-datepicker-today":""))+'"'+((!otherMonth||showOtherMonths)&&daySettings[2]?' title="'+daySettings[2]+'"':"")+(unselectable?"":" onclick=\"DP_jQuery.datepicker._selectDay('#"+inst.id+"',"+drawMonth+","+drawYear+', this);return false;"')+">"+(otherMonth?(showOtherMonths?printDate.getDate():" "):(unselectable?''+printDate.getDate()+"":'=currentDate.getTime()&&printDate.getTime()<=endDate.getTime()?" ui-state-active":"")+'" href="#">'+printDate.getDate()+""))+"
                          "+(isMultiMonth?"
                          "+((numMonths[0]>0&&col==numMonths[1]-1)?'
                          ':""):"");group+=calender}html+=group}html+=buttonPanel+($.browser.msie&&parseInt($.browser.version,10)<7&&!inst.inline?'':"");inst._keyEvent=false;return html},_generateMonthYearHeader:function(inst,drawMonth,drawYear,minDate,maxDate,selectedDate,secondary,monthNames,monthNamesShort){minDate=(inst.rangeStart&&minDate&&selectedDate "}else{var inMinYear=(minDate&&minDate.getFullYear()==drawYear);var inMaxYear=(maxDate&&maxDate.getFullYear()==drawYear);monthHtml+='"}if(!showMonthAfterYear){html+=monthHtml+((secondary||changeMonth||changeYear)&&(!(changeMonth&&changeYear))?" ":"")}if(secondary||!changeYear){html+=''+drawYear+""}else{var years=this._get(inst,"yearRange").split(":");var year=0;var endYear=0;if(years.length!=2){year=drawYear-10;endYear=drawYear+10}else{if(years[0].charAt(0)=="+"||years[0].charAt(0)=="-"){year=drawYear+parseInt(years[0],10);endYear=drawYear+parseInt(years[1],10)}else{year=parseInt(years[0],10);endYear=parseInt(years[1],10)}}year=(minDate?Math.max(year,minDate.getFullYear()):year);endYear=(maxDate?Math.min(endYear,maxDate.getFullYear()):endYear);html+='"}if(showMonthAfterYear){html+=(secondary||changeMonth||changeYear?" ":"")+monthHtml}html+="
                          ";return html},_adjustInstDate:function(inst,offset,period){var year=inst.drawYear+(period=="Y"?offset:0);var month=inst.drawMonth+(period=="M"?offset:0);var day=Math.min(inst.selectedDay,this._getDaysInMonth(year,month))+(period=="D"?offset:0);var date=this._daylightSavingAdjust(new Date(year,month,day));var minDate=this._getMinMaxDate(inst,"min",true);var maxDate=this._getMinMaxDate(inst,"max");date=(minDate&&datemaxDate?maxDate:date);inst.selectedDay=date.getDate();inst.drawMonth=inst.selectedMonth=date.getMonth();inst.drawYear=inst.selectedYear=date.getFullYear();if(period=="M"||period=="Y"){this._notifyChange(inst)}},_notifyChange:function(inst){var onChange=this._get(inst,"onChangeMonthYear");if(onChange){onChange.apply((inst.input?inst.input[0]:null),[inst.selectedYear,inst.selectedMonth+1,inst])}},_getNumberOfMonths:function(inst){var numMonths=this._get(inst,"numberOfMonths");return(numMonths==null?[1,1]:(typeof numMonths=="number"?[1,numMonths]:numMonths))},_getMinMaxDate:function(inst,minMax,checkRange){var date=this._determineDate(this._get(inst,minMax+"Date"),null);return(!checkRange||!inst.rangeStart?date:(!date||inst.rangeStart>date?inst.rangeStart:date))},_getDaysInMonth:function(year,month){return 32-new Date(year,month,32).getDate()},_getFirstDayOfMonth:function(year,month){return new Date(year,month,1).getDay()},_canAdjustMonth:function(inst,offset,curYear,curMonth){var numMonths=this._getNumberOfMonths(inst);var date=this._daylightSavingAdjust(new Date(curYear,curMonth+(offset<0?offset:numMonths[1]),1));if(offset<0){date.setDate(this._getDaysInMonth(date.getFullYear(),date.getMonth()))}return this._isInRange(inst,date)},_isInRange:function(inst,date){var newMinDate=(!inst.rangeStart?null:this._daylightSavingAdjust(new Date(inst.selectedYear,inst.selectedMonth,inst.selectedDay)));newMinDate=(newMinDate&&inst.rangeStart=minDate)&&(!maxDate||date<=maxDate))},_getFormatConfig:function(inst){var shortYearCutoff=this._get(inst,"shortYearCutoff");shortYearCutoff=(typeof shortYearCutoff!="string"?shortYearCutoff:new Date().getFullYear()%100+parseInt(shortYearCutoff,10));return{shortYearCutoff:shortYearCutoff,dayNamesShort:this._get(inst,"dayNamesShort"),dayNames:this._get(inst,"dayNames"),monthNamesShort:this._get(inst,"monthNamesShort"),monthNames:this._get(inst,"monthNames")}},_formatDate:function(inst,day,month,year){if(!day){inst.currentDay=inst.selectedDay;inst.currentMonth=inst.selectedMonth;inst.currentYear=inst.selectedYear}var date=(day?(typeof day=="object"?day:this._daylightSavingAdjust(new Date(year,month,day))):this._daylightSavingAdjust(new Date(inst.currentYear,inst.currentMonth,inst.currentDay)));return this.formatDate(this._get(inst,"dateFormat"),date,this._getFormatConfig(inst))}});function extendRemove(target,props){$.extend(target,props);for(var name in props){if(props[name]==null||props[name]==undefined){target[name]=props[name]}}return target}function isArray(a){return(a&&(($.browser.safari&&typeof a=="object"&&a.length)||(a.constructor&&a.constructor.toString().match(/\Array\(\)/))))}$.fn.datepicker=function(options){if(!$.datepicker.initialized){$(document).mousedown($.datepicker._checkExternalClick).find("body").append($.datepicker.dpDiv);$.datepicker.initialized=true}var otherArgs=Array.prototype.slice.call(arguments,1);if(typeof options=="string"&&(options=="isDisabled"||options=="getDate")){return $.datepicker["_"+options+"Datepicker"].apply($.datepicker,[this[0]].concat(otherArgs))}if(options=="option"&&arguments.length==2&&typeof arguments[1]=="string"){return $.datepicker["_"+options+"Datepicker"].apply($.datepicker,[this[0]].concat(otherArgs))}return this.each(function(){typeof options=="string"?$.datepicker["_"+options+"Datepicker"].apply($.datepicker,[this].concat(otherArgs)):$.datepicker._attachDatepicker(this,options)})};$.datepicker=new Datepicker();$.datepicker.initialized=false;$.datepicker.uuid=new Date().getTime();$.datepicker.version="1.7.2";window.DP_jQuery=$})(jQuery);;/* * jQuery UI Progressbar 1.7.2 * * Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about) @@ -163,4 +139,511 @@ jQuery.effects||(function(d){d.effects={version:"1.7.2",save:function(g,h){for(v * Depends: * effects.core.js */ -(function(a){a.effects.transfer=function(b){return this.queue(function(){var f=a(this),h=a(b.options.to),e=h.offset(),g={top:e.top,left:e.left,height:h.innerHeight(),width:h.innerWidth()},d=f.offset(),c=a('
                          ').appendTo(document.body).addClass(b.options.className).css({top:d.top,left:d.left,height:f.innerHeight(),width:f.innerWidth(),position:"absolute"}).animate(g,b.duration,b.options.easing,function(){c.remove();(b.callback&&b.callback.apply(f[0],arguments));f.dequeue()})})}})(jQuery);; \ No newline at end of file +(function(a){a.effects.transfer=function(b){return this.queue(function(){var f=a(this),h=a(b.options.to),e=h.offset(),g={top:e.top,left:e.left,height:h.innerHeight(),width:h.innerWidth()},d=f.offset(),c=a('
                          ').appendTo(document.body).addClass(b.options.className).css({top:d.top,left:d.left,height:f.innerHeight(),width:f.innerWidth(),position:"absolute"}).animate(g,b.duration,b.options.easing,function(){c.remove();(b.callback&&b.callback.apply(f[0],arguments));f.dequeue()})})}})(jQuery);;/* + * jQuery UI Selectable @VERSION + * + * Copyright (c) 2009 AUTHORS.txt (http://ui.jquery.com/about) + * Dual licensed under the MIT (MIT-LICENSE.txt) + * and GPL (GPL-LICENSE.txt) licenses. + * + * http://docs.jquery.com/UI/Selectables + * + * Depends: + * ui.core.js + */ +(function($) { + + $.widget('ui.selectable', $.extend({}, $.ui.mouse, { + + _init: function() { + + var self = this; + this.items = $(this.options.filter, this.element); + this.element.addClass("ui-selectable"); + + //Set the currentFocus to the first item + this.currentFocus = this.items.eq(0); + + //Refresh item positions + this.refresh(); + + //Disable text selection + this.element.disableSelection(); + + //Prepare caret selection + if(this.options.lasso) this._mouseInit(); + + this.element + .bind('mousedown.selectable', function(event) { + + var item = self._targetIsItem(event.target); + if (!item) return; + + // If item is part of current selection and current + // selection is multiple, return and allow mouseup + // to fire (Windows gets this right too, OSX doesn't) + if(self._selection.length > 1 && $(item).hasClass(self.options.selectedClass)) { + return (self._listenForMouseUp = 1); + } + + if(self._trigger('beforeselect', event) === false) + return true; + + self._select(event, item); + self.element[0].focus(); + event.preventDefault(); + + }) + .bind('mouseup.selectable', function(event) { + if(self._listenForMouseUp) { + + self._listenForMouseUp = 0; + var item = self._targetIsItem(event.target); + if (!item) return; + + if(self._trigger('beforeselect', event) === false) + return true; + + self._select(event, item); + self.element[0].focus(); + event.preventDefault(); + } + }) + .bind('focus.selectable', function() { + self.currentFocus.addClass('ui-focused'); + }) + .bind('blur.selectable', function() { + self.currentFocus.removeClass('ui-focused'); + }) + .bind('keydown.selectable', function(event) { + + if(!self.options.keyboard) + return; + + if(self._trigger('beforeselect', event) === false) + return true; + + if(event.keyCode == $.ui.keyCode.DOWN) { + self.options.smart ? self.selectClosest('down', event) : self.selectNext(event); + event.preventDefault(); + } + + if(event.keyCode == $.ui.keyCode.RIGHT) { + self.options.smart ? self.selectClosest('right', event) : self.selectNext(event); + event.preventDefault(); + } + + if(event.keyCode == $.ui.keyCode.UP) { + self.options.smart ? self.selectClosest('up', event) : self.selectPrevious(event); + event.preventDefault(); + } + + if(event.keyCode == $.ui.keyCode.LEFT) { + self.options.smart ? self.selectClosest('left', event) : self.selectPrevious(event); + event.preventDefault(); + } + + if ((event.ctrlKey || event.metaKey) && event.keyCode == $.ui.keyCode.SPACE) { + self._toggleSelection(self.currentFocus, event); + } + + }); + + this.helper = $(document.createElement('div')) + .addClass("ui-selectable-lasso"); + + }, + + selectClosest: function(direction, event) { + + var current = [/(down|right)/.test(direction) ? 10000 : -10000, null], + overlap = 10000, + selfOffset = this.currentFocus.data('selectable-item'); + + $(this.options.filter, this.element).not(this.currentFocus).filter(':visible').each(function() { + + var $this = $(this), + offset = $this.data('selectable-item'), + distance = { + x: Math.abs(selfOffset.left - offset.left) + Math.abs((offset.left+this.offsetWidth) - (selfOffset.left+this.offsetWidth)), + y: Math.abs(selfOffset.top - offset.top) + Math.abs((offset.top+this.offsetHeight) - (selfOffset.top+this.offsetHeight)) + }; + + switch(direction) { + + case 'up': + if((selfOffset.top > offset.top && offset.top >= current[0]) && (offset.top != current[0] || distance.x < overlap)) { + current = [offset.top, $this]; + overlap = distance.x; + } + break; + + case 'down': + if((selfOffset.top < offset.top && offset.top <= current[0]) && (offset.top != current[0] || distance.x < overlap)) { + current = [offset.top, $this]; + overlap = distance.x; + } + break; + + case 'left': + if((selfOffset.left > offset.left && offset.left >= current[0]) && (offset.left != current[0] || distance.y < overlap)) { + current = [offset.left, $this]; + overlap = distance.y; + } + break; + + case 'right': + if((selfOffset.left < offset.left && offset.left <= current[0]) && (offset.left != current[0] || distance.y < overlap)) { + current = [offset.left, $this]; + overlap = distance.y; + } + break; + + } + + }); + + return current[1] ? this._select(event, current[1]) : false; + + }, + + destroy: function() { + this.element + .removeClass("ui-selectable ui-selectable-disabled") + .removeData("selectable") + .unbind(".selectable"); + this._mouseDestroy(); + }, + + _mouseCapture: function(event) { + //If the item we start dragging on is a selectable, we bail (if keyboard is used) + this.clickedOnItem = this._targetIsItem(event.target); + return !this.options.keyboard || !this.clickedOnItem; + }, + + _mouseStart: function(event) { + + var self = this, o = this.options; + this.opos = [event.pageX, event.pageY]; + + if (o.disabled) + return; + + //Cache positions + this.refresh(); + + //Trigger start event + this._trigger("start", event, this._uiHash()); + + // append and position helper (lasso) + $('body').append(this.helper); + this.helper.css({ + zIndex: 100, + position: "absolute", + left: event.clientX, + top: event.clientY, + width: 0, + height: 0 + }); + + //Tell the intersection that some start selected + this.items.filter('.'+this.options.selectedClass).each(function() { + if(event.metaKey) { + if(this != self.clickedOnItem) $.data(this, "selectable-item").startSelected = true; + } else self._removeFromSelection($(this), event); + }); + + }, + + _mouseDrag: function(event) { + + var self = this, o = this.options; + + if (o.disabled) + return; + + //Do the lasso magic + var x1 = this.opos[0], y1 = this.opos[1], x2 = event.pageX, y2 = event.pageY; + if (x1 > x2) { var tmp = x2; x2 = x1; x1 = tmp; } + if (y1 > y2) { var tmp = y2; y2 = y1; y1 = tmp; } + this.helper.css({left: x1, top: y1, width: x2-x1, height: y2-y1}); + + //Loop through all items and check overlaps + this.items.each(function() { + + var item = $.data(this, "selectable-item"); + + //prevent helper from being selected if appendTo: selectable + if (!item || item.element == self.element[0]) + return; + + var hit = false; + if (o.lasso && o.lasso.tolerance == 'touch') { + hit = ( !(item.left > x2 || item.right < x1 || item.top > y2 || item.bottom < y1) ); + } else if (o.lasso && o.lasso.tolerance == 'fit') { + hit = (item.left > x1 && item.right < x2 && item.top > y1 && item.bottom < y2); + } + + hit ? + item.startSelected ? self._removeFromSelection($(this), event) : self._addToSelection($(this), event) + : !item.startSelected ? self._removeFromSelection($(this), event) : self._addToSelection($(this), event); + + }); + + return false; + + }, + + _mouseStop: function(event) { + this._trigger("stop", event, this._uiHash()); + this.helper.remove(); + return false; + }, + + _targetIsItem: function(item) { + var found = $(item).parents().andSelf().filter(':data(selectable-item)'); + return found.length && found; + }, + + _selection: [], + + _clearSelection: function(triggerEvent) { + + var triggerItems = []; + + for (var i = this._selection.length - 1; i >= 0; i--){ + if(triggerEvent && this._selection[i].data('selectable-item').selected) triggerItems.push(this._selection[i]); + this._selection[i].removeClass(this.options.selectedClass); + this._selection[i].data('selectable-item').selected = false; + }; + + this._selection = []; + if(triggerEvent) this._trigger('unselect', triggerEvent, this._uiHash($($.map(triggerItems, function(i) { return i[0]; })), 'removed')); + + }, + + _toggleSelection: function(item, event) { + item.data('selectable-item').selected ? this._removeFromSelection(item, event) : this._addToSelection(item); + }, + + _addToSelection: function(item, triggerEvent) { + + if (item.data('selectable-item').selected) + return null; + + this._selection.push(item); + this.latestSelection = item; + item.addClass(this.options.selectedClass); + item.data('selectable-item').selected = true; + + if(triggerEvent) { + this._trigger('select', triggerEvent, $.extend({ lasso: true }, this._uiHash(item))); + } + + return item; + + }, + + _removeFromSelection: function(item, triggerEvent) { + + for (var i=0; i < this._selection.length; i++) { + if (this._selection[i][0] == item[0]) { + this._selection[i].removeClass(this.options.selectedClass); + this._selection[i].data('selectable-item').selected = false; + this._selection.splice(i,1); + if(triggerEvent) this._trigger('unselect', triggerEvent, this._uiHash($(item), 'removed')); + break; + } + }; + + }, + + _updateSelectionMouse: function(event) { + + var newlySelected = []; + + if (event.shiftKey && this.options.multiple) { + + //Clear the previous selection to make room for a shift selection + this._clearSelection(event); + + var index = this.items.index(this.latestWithoutModifier[0]) > this.items.index(this.currentFocus[0]) ? -1 : 1; + var i = this.latestWithoutModifier.data('selectable-item').selected ? this.items.eq(this.items.index(this.latestWithoutModifier[0])+index) : this.latestWithoutModifier; + while(i.length && i[0] != this.currentFocus[0]) { + i[0] == this.previousFocus[0] ? this._addToSelection(i) : newlySelected.push(this._addToSelection(i)); + i = this.items.eq(this.items.index(i[0])+index); + } + + //Readd the item with the current focus + newlySelected.push(this._addToSelection(this.currentFocus)); + + } else { + + if (event.metaKey) { + this._toggleSelection(this.currentFocus, event); + } else { + this._clearSelection(event); + newlySelected.push(this._addToSelection(this.currentFocus)); + this.latestWithoutModifier = this.currentFocus; + } + + } + + return $($.map(newlySelected, function(i) { return i[0]; })); + + }, + + _updateSelection: function(event, index) { + + var newlySelected = []; + + if (event.shiftKey && this.options.multiple) { + + if (this.currentFocus.data('selectable-item').selected) { + this._removeFromSelection(this.previousFocus, event); + } else { + + var index2 = this.items.index(this.latestSelection[0]) > this.items.index(this.currentFocus[0]) ? 1 : -1; + if (!this.previousFocus.data('selectable-item').selected) { + var i = index == index2 ? this.items.eq(this.items.index(this.previousFocus[0])+index2) : this.previousFocus; + while(i.length && !i.data('selectable-item').selected) { + newlySelected.push(this._addToSelection(i)); + i = this.items.eq(this.items.index(i[0])+index2); + } + } + + newlySelected.push(this._addToSelection(this.currentFocus)); + + } + + } else { + + //If the CTRL or Apple/Win key is pressed, only set focus + if (event.metaKey) + return; + + this._clearSelection(event); + newlySelected.push(this._addToSelection(this.currentFocus)); + this.latestWithoutModifier = this.currentFocus; + + } + + return $($.map(newlySelected, function(i) { return i[0]; })); + + }, + + _select: function(event, item) { + + //Set the current selection to the previous/next item + this.previousFocus = this.currentFocus; + this.currentFocus = $(item); + + this.previousFocus.removeClass('ui-focused'); + this.currentFocus.addClass('ui-focused'); + + //Set and update the selection + var newlySelected = this._updateSelectionMouse(event); + + //Trigger select event + if(newlySelected && newlySelected.length) this._trigger('select', event, this._uiHash(newlySelected, 'added')); + + }, + + _selectAdjacent: function(event, index) { + + var item = this.items.eq(this.items.index(this.currentFocus[0]) + index); + + //Bail if there's no previous/next item + if (!item.length) return; + + //Set the current selection to the previous/next item + this.previousFocus = this.currentFocus; + this.currentFocus = item; + + this.previousFocus.removeClass('ui-focused'); + this.currentFocus.addClass('ui-focused'); + + //Set and update the selection + var newlySelected = this._updateSelection(event, index); + + //Trigger select event + if(newlySelected && newlySelected.length) this._trigger('select', event, this._uiHash(newlySelected, 'added')); + + }, + + selectPrevious: function(event) { + this._selectAdjacent(event, -1); + }, + + selectNext: function(event) { + this._selectAdjacent(event, 1); + }, + + refresh: function() { + + var o = this.options; + this.items = $(o.filter, this.element); + this.items.each(function() { + var $this = $(this); + var pos = $this.offset(); + $.data(this, "selectable-item", { + left: pos.left, + top: pos.top, + right: pos.left + $this.width(), + bottom: pos.top + $this.height(), + startSelected: false, + selected: $this.hasClass(o.selectedClass) + }); + }); + + }, + + select: function(item) { + //TODO + }, + + deselect: function(item) { + if(!item) this._clearSelection(true); + //TODO: Deselect single elements + }, + + _uiHash: function(items, specialKey) { + var uiHash = { + previousFocus: this.previousFocus, + currentFocus: this.currentFocus, + selection: $($.map(this._selection, function(i) { return i[0]; })) + }; + if(specialKey) uiHash[specialKey] = items; + return uiHash; + } + + })); + + $.extend($.ui.selectable, { + defaults: { + + //TODO: Figure out how to move these defaults out + cancel: ":input,option", + delay: 0, + distance: 1, + appendTo: 'body', + + multiple: true, + smart: true, + filter: '> *', + + keyboard: true, + lasso: { + cancel: ":input,option", + delay: 0, + distance: 1, + tolerance: 'touch', + appendTo: 'body' + }, + + //Should we really delete that? + selectedClass: 'ui-state-selected' + } + }); + +})(jQuery); -- cgit v1.2.3 From 693e95e7b092fdbbae6ab59314230d234efffd5b Mon Sep 17 00:00:00 2001 From: Tim Almdal Date: Thu, 13 Aug 2009 05:13:39 +0800 Subject: Use the jquery-ui library that contains a prerelease version of the slectable component Signed-off-by: Tim Almdal --- lib/jquery-ui.js | 533 ++++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 508 insertions(+), 25 deletions(-) diff --git a/lib/jquery-ui.js b/lib/jquery-ui.js index 0c6a0ebe..4939d009 100644 --- a/lib/jquery-ui.js +++ b/lib/jquery-ui.js @@ -45,18 +45,6 @@ jQuery.ui||(function(c){var i=c.fn.remove,d=c.browser.mozilla&&(parseFloat(c.bro * ui.core.js */ (function(c){c.widget("ui.resizable",c.extend({},c.ui.mouse,{_init:function(){var e=this,j=this.options;this.element.addClass("ui-resizable");c.extend(this,{_aspectRatio:!!(j.aspectRatio),aspectRatio:j.aspectRatio,originalElement:this.element,_proportionallyResizeElements:[],_helper:j.helper||j.ghost||j.animate?j.helper||"ui-resizable-helper":null});if(this.element[0].nodeName.match(/canvas|textarea|input|select|button|img/i)){if(/relative/.test(this.element.css("position"))&&c.browser.opera){this.element.css({position:"relative",top:"auto",left:"auto"})}this.element.wrap(c('
                          ').css({position:this.element.css("position"),width:this.element.outerWidth(),height:this.element.outerHeight(),top:this.element.css("top"),left:this.element.css("left")}));this.element=this.element.parent().data("resizable",this.element.data("resizable"));this.elementIsWrapper=true;this.element.css({marginLeft:this.originalElement.css("marginLeft"),marginTop:this.originalElement.css("marginTop"),marginRight:this.originalElement.css("marginRight"),marginBottom:this.originalElement.css("marginBottom")});this.originalElement.css({marginLeft:0,marginTop:0,marginRight:0,marginBottom:0});this.originalResizeStyle=this.originalElement.css("resize");this.originalElement.css("resize","none");this._proportionallyResizeElements.push(this.originalElement.css({position:"static",zoom:1,display:"block"}));this.originalElement.css({margin:this.originalElement.css("margin")});this._proportionallyResize()}this.handles=j.handles||(!c(".ui-resizable-handle",this.element).length?"e,s,se":{n:".ui-resizable-n",e:".ui-resizable-e",s:".ui-resizable-s",w:".ui-resizable-w",se:".ui-resizable-se",sw:".ui-resizable-sw",ne:".ui-resizable-ne",nw:".ui-resizable-nw"});if(this.handles.constructor==String){if(this.handles=="all"){this.handles="n,e,s,w,se,sw,ne,nw"}var k=this.handles.split(",");this.handles={};for(var f=0;f
                          ');if(/sw|se|ne|nw/.test(h)){g.css({zIndex:++j.zIndex})}if("se"==h){g.addClass("ui-icon ui-icon-gripsmall-diagonal-se")}this.handles[h]=".ui-resizable-"+h;this.element.append(g)}}this._renderAxis=function(p){p=p||this.element;for(var m in this.handles){if(this.handles[m].constructor==String){this.handles[m]=c(this.handles[m],this.element).show()}if(this.elementIsWrapper&&this.originalElement[0].nodeName.match(/textarea|input|select|button/i)){var n=c(this.handles[m],this.element),o=0;o=/sw|ne|nw|se|n|s/.test(m)?n.outerHeight():n.outerWidth();var l=["padding",/ne|nw|n/.test(m)?"Top":/se|sw|s/.test(m)?"Bottom":/^e$/.test(m)?"Right":"Left"].join("");p.css(l,o);this._proportionallyResize()}if(!c(this.handles[m]).length){continue}}};this._renderAxis(this.element);this._handles=c(".ui-resizable-handle",this.element).disableSelection();this._handles.mouseover(function(){if(!e.resizing){if(this.className){var i=this.className.match(/ui-resizable-(se|sw|ne|nw|n|e|s|w)/i)}e.axis=i&&i[1]?i[1]:"se"}});if(j.autoHide){this._handles.hide();c(this.element).addClass("ui-resizable-autohide").hover(function(){c(this).removeClass("ui-resizable-autohide");e._handles.show()},function(){if(!e.resizing){c(this).addClass("ui-resizable-autohide");e._handles.hide()}})}this._mouseInit()},destroy:function(){this._mouseDestroy();var d=function(f){c(f).removeClass("ui-resizable ui-resizable-disabled ui-resizable-resizing").removeData("resizable").unbind(".resizable").find(".ui-resizable-handle").remove()};if(this.elementIsWrapper){d(this.element);var e=this.element;e.parent().append(this.originalElement.css({position:e.css("position"),width:e.outerWidth(),height:e.outerHeight(),top:e.css("top"),left:e.css("left")})).end().remove()}this.originalElement.css("resize",this.originalResizeStyle);d(this.originalElement)},_mouseCapture:function(e){var f=false;for(var d in this.handles){if(c(this.handles[d])[0]==e.target){f=true}}return this.options.disabled||!!f},_mouseStart:function(f){var i=this.options,e=this.element.position(),d=this.element;this.resizing=true;this.documentScroll={top:c(document).scrollTop(),left:c(document).scrollLeft()};if(d.is(".ui-draggable")||(/absolute/).test(d.css("position"))){d.css({position:"absolute",top:e.top,left:e.left})}if(c.browser.opera&&(/relative/).test(d.css("position"))){d.css({position:"relative",top:"auto",left:"auto"})}this._renderProxy();var j=b(this.helper.css("left")),g=b(this.helper.css("top"));if(i.containment){j+=c(i.containment).scrollLeft()||0;g+=c(i.containment).scrollTop()||0}this.offset=this.helper.offset();this.position={left:j,top:g};this.size=this._helper?{width:d.outerWidth(),height:d.outerHeight()}:{width:d.width(),height:d.height()};this.originalSize=this._helper?{width:d.outerWidth(),height:d.outerHeight()}:{width:d.width(),height:d.height()};this.originalPosition={left:j,top:g};this.sizeDiff={width:d.outerWidth()-d.width(),height:d.outerHeight()-d.height()};this.originalMousePosition={left:f.pageX,top:f.pageY};this.aspectRatio=(typeof i.aspectRatio=="number")?i.aspectRatio:((this.originalSize.width/this.originalSize.height)||1);var h=c(".ui-resizable-"+this.axis).css("cursor");c("body").css("cursor",h=="auto"?this.axis+"-resize":h);d.addClass("ui-resizable-resizing");this._propagate("start",f);return true},_mouseDrag:function(d){var g=this.helper,f=this.options,l={},p=this,i=this.originalMousePosition,m=this.axis;var q=(d.pageX-i.left)||0,n=(d.pageY-i.top)||0;var h=this._change[m];if(!h){return false}var k=h.apply(this,[d,q,n]),j=c.browser.msie&&c.browser.version<7,e=this.sizeDiff;if(this._aspectRatio||d.shiftKey){k=this._updateRatio(k,d)}k=this._respectSize(k,d);this._propagate("resize",d);g.css({top:this.position.top+"px",left:this.position.left+"px",width:this.size.width+"px",height:this.size.height+"px"});if(!this._helper&&this._proportionallyResizeElements.length){this._proportionallyResize()}this._updateCache(k);this._trigger("resize",d,this.ui());return false},_mouseStop:function(g){this.resizing=false;var h=this.options,l=this;if(this._helper){var f=this._proportionallyResizeElements,d=f.length&&(/textarea/i).test(f[0].nodeName),e=d&&c.ui.hasScroll(f[0],"left")?0:l.sizeDiff.height,j=d?0:l.sizeDiff.width;var m={width:(l.size.width-j),height:(l.size.height-e)},i=(parseInt(l.element.css("left"),10)+(l.position.left-l.originalPosition.left))||null,k=(parseInt(l.element.css("top"),10)+(l.position.top-l.originalPosition.top))||null;if(!h.animate){this.element.css(c.extend(m,{top:k,left:i}))}l.helper.height(l.size.height);l.helper.width(l.size.width);if(this._helper&&!h.animate){this._proportionallyResize()}}c("body").css("cursor","auto");this.element.removeClass("ui-resizable-resizing");this._propagate("stop",g);if(this._helper){this.helper.remove()}return false},_updateCache:function(d){var e=this.options;this.offset=this.helper.offset();if(a(d.left)){this.position.left=d.left}if(a(d.top)){this.position.top=d.top}if(a(d.height)){this.size.height=d.height}if(a(d.width)){this.size.width=d.width}},_updateRatio:function(g,f){var h=this.options,i=this.position,e=this.size,d=this.axis;if(g.height){g.width=(e.height*this.aspectRatio)}else{if(g.width){g.height=(e.width/this.aspectRatio)}}if(d=="sw"){g.left=i.left+(e.width-g.width);g.top=null}if(d=="nw"){g.top=i.top+(e.height-g.height);g.left=i.left+(e.width-g.width)}return g},_respectSize:function(k,f){var i=this.helper,h=this.options,q=this._aspectRatio||f.shiftKey,p=this.axis,s=a(k.width)&&h.maxWidth&&(h.maxWidthk.width),r=a(k.height)&&h.minHeight&&(h.minHeight>k.height);if(g){k.width=h.minWidth}if(r){k.height=h.minHeight}if(s){k.width=h.maxWidth}if(l){k.height=h.maxHeight}var e=this.originalPosition.left+this.originalSize.width,n=this.position.top+this.size.height;var j=/sw|nw|w/.test(p),d=/nw|ne|n/.test(p);if(g&&j){k.left=e-h.minWidth}if(s&&j){k.left=e-h.maxWidth}if(r&&d){k.top=n-h.minHeight}if(l&&d){k.top=n-h.maxHeight}var m=!k.width&&!k.height;if(m&&!k.left&&k.top){k.top=null}else{if(m&&!k.top&&k.left){k.left=null}}return k},_proportionallyResize:function(){var j=this.options;if(!this._proportionallyResizeElements.length){return}var f=this.helper||this.element;for(var e=0;e
                          ');var d=c.browser.msie&&c.browser.version<7,f=(d?1:0),g=(d?2:-1);this.helper.addClass(this._helper).css({width:this.element.outerWidth()+g,height:this.element.outerHeight()+g,position:"absolute",left:this.elementOffset.left-f+"px",top:this.elementOffset.top-f+"px",zIndex:++h.zIndex});this.helper.appendTo("body").disableSelection()}else{this.helper=this.element}},_change:{e:function(f,e,d){return{width:this.originalSize.width+e}},w:function(g,e,d){var i=this.options,f=this.originalSize,h=this.originalPosition;return{left:h.left+e,width:f.width-e}},n:function(g,e,d){var i=this.options,f=this.originalSize,h=this.originalPosition;return{top:h.top+d,height:f.height-d}},s:function(f,e,d){return{height:this.originalSize.height+d}},se:function(f,e,d){return c.extend(this._change.s.apply(this,arguments),this._change.e.apply(this,[f,e,d]))},sw:function(f,e,d){return c.extend(this._change.s.apply(this,arguments),this._change.w.apply(this,[f,e,d]))},ne:function(f,e,d){return c.extend(this._change.n.apply(this,arguments),this._change.e.apply(this,[f,e,d]))},nw:function(f,e,d){return c.extend(this._change.n.apply(this,arguments),this._change.w.apply(this,[f,e,d]))}},_propagate:function(e,d){c.ui.plugin.call(this,e,[d,this.ui()]);(e!="resize"&&this._trigger(e,d,this.ui()))},plugins:{},ui:function(){return{originalElement:this.originalElement,element:this.element,helper:this.helper,position:this.position,size:this.size,originalSize:this.originalSize,originalPosition:this.originalPosition}}}));c.extend(c.ui.resizable,{version:"1.7.2",eventPrefix:"resize",defaults:{alsoResize:false,animate:false,animateDuration:"slow",animateEasing:"swing",aspectRatio:false,autoHide:false,cancel:":input,option",containment:false,delay:0,distance:1,ghost:false,grid:false,handles:"e,s,se",helper:false,maxHeight:null,maxWidth:null,minHeight:10,minWidth:10,zIndex:1000}});c.ui.plugin.add("resizable","alsoResize",{start:function(e,f){var d=c(this).data("resizable"),g=d.options;_store=function(h){c(h).each(function(){c(this).data("resizable-alsoresize",{width:parseInt(c(this).width(),10),height:parseInt(c(this).height(),10),left:parseInt(c(this).css("left"),10),top:parseInt(c(this).css("top"),10)})})};if(typeof(g.alsoResize)=="object"&&!g.alsoResize.parentNode){if(g.alsoResize.length){g.alsoResize=g.alsoResize[0];_store(g.alsoResize)}else{c.each(g.alsoResize,function(h,i){_store(h)})}}else{_store(g.alsoResize)}},resize:function(f,h){var e=c(this).data("resizable"),i=e.options,g=e.originalSize,k=e.originalPosition;var j={height:(e.size.height-g.height)||0,width:(e.size.width-g.width)||0,top:(e.position.top-k.top)||0,left:(e.position.left-k.left)||0},d=function(l,m){c(l).each(function(){var p=c(this),q=c(this).data("resizable-alsoresize"),o={},n=m&&m.length?m:["width","height","top","left"];c.each(n||["width","height","top","left"],function(r,t){var s=(q[t]||0)+(j[t]||0);if(s&&s>=0){o[t]=s||null}});if(/relative/.test(p.css("position"))&&c.browser.opera){e._revertToRelativePosition=true;p.css({position:"absolute",top:"auto",left:"auto"})}p.css(o)})};if(typeof(i.alsoResize)=="object"&&!i.alsoResize.nodeType){c.each(i.alsoResize,function(l,m){d(l,m)})}else{d(i.alsoResize)}},stop:function(e,f){var d=c(this).data("resizable");if(d._revertToRelativePosition&&c.browser.opera){d._revertToRelativePosition=false;el.css({position:"relative"})}c(this).removeData("resizable-alsoresize-start")}});c.ui.plugin.add("resizable","animate",{stop:function(h,m){var n=c(this).data("resizable"),i=n.options;var g=n._proportionallyResizeElements,d=g.length&&(/textarea/i).test(g[0].nodeName),e=d&&c.ui.hasScroll(g[0],"left")?0:n.sizeDiff.height,k=d?0:n.sizeDiff.width;var f={width:(n.size.width-k),height:(n.size.height-e)},j=(parseInt(n.element.css("left"),10)+(n.position.left-n.originalPosition.left))||null,l=(parseInt(n.element.css("top"),10)+(n.position.top-n.originalPosition.top))||null;n.element.animate(c.extend(f,l&&j?{top:l,left:j}:{}),{duration:i.animateDuration,easing:i.animateEasing,step:function(){var o={width:parseInt(n.element.css("width"),10),height:parseInt(n.element.css("height"),10),top:parseInt(n.element.css("top"),10),left:parseInt(n.element.css("left"),10)};if(g&&g.length){c(g[0]).css({width:o.width,height:o.height})}n._updateCache(o);n._propagate("resize",h)}})}});c.ui.plugin.add("resizable","containment",{start:function(e,q){var s=c(this).data("resizable"),i=s.options,k=s.element;var f=i.containment,j=(f instanceof c)?f.get(0):(/parent/.test(f))?k.parent().get(0):f;if(!j){return}s.containerElement=c(j);if(/document/.test(f)||f==document){s.containerOffset={left:0,top:0};s.containerPosition={left:0,top:0};s.parentData={element:c(document),left:0,top:0,width:c(document).width(),height:c(document).height()||document.body.parentNode.scrollHeight}}else{var m=c(j),h=[];c(["Top","Right","Left","Bottom"]).each(function(p,o){h[p]=b(m.css("padding"+o))});s.containerOffset=m.offset();s.containerPosition=m.position();s.containerSize={height:(m.innerHeight()-h[3]),width:(m.innerWidth()-h[1])};var n=s.containerOffset,d=s.containerSize.height,l=s.containerSize.width,g=(c.ui.hasScroll(j,"left")?j.scrollWidth:l),r=(c.ui.hasScroll(j)?j.scrollHeight:d);s.parentData={element:j,left:n.left,top:n.top,width:g,height:r}}},resize:function(f,p){var s=c(this).data("resizable"),h=s.options,e=s.containerSize,n=s.containerOffset,l=s.size,m=s.position,q=s._aspectRatio||f.shiftKey,d={top:0,left:0},g=s.containerElement;if(g[0]!=document&&(/static/).test(g.css("position"))){d=n}if(m.left<(s._helper?n.left:0)){s.size.width=s.size.width+(s._helper?(s.position.left-n.left):(s.position.left-d.left));if(q){s.size.height=s.size.width/h.aspectRatio}s.position.left=h.helper?n.left:0}if(m.top<(s._helper?n.top:0)){s.size.height=s.size.height+(s._helper?(s.position.top-n.top):s.position.top);if(q){s.size.width=s.size.height*h.aspectRatio}s.position.top=s._helper?n.top:0}s.offset.left=s.parentData.left+s.position.left;s.offset.top=s.parentData.top+s.position.top;var k=Math.abs((s._helper?s.offset.left-d.left:(s.offset.left-d.left))+s.sizeDiff.width),r=Math.abs((s._helper?s.offset.top-d.top:(s.offset.top-n.top))+s.sizeDiff.height);var j=s.containerElement.get(0)==s.element.parent().get(0),i=/relative|absolute/.test(s.containerElement.css("position"));if(j&&i){k-=s.parentData.left}if(k+s.size.width>=s.parentData.width){s.size.width=s.parentData.width-k;if(q){s.size.height=s.size.width/s.aspectRatio}}if(r+s.size.height>=s.parentData.height){s.size.height=s.parentData.height-r;if(q){s.size.width=s.size.height*s.aspectRatio}}},stop:function(e,m){var p=c(this).data("resizable"),f=p.options,k=p.position,l=p.containerOffset,d=p.containerPosition,g=p.containerElement;var i=c(p.helper),q=i.offset(),n=i.outerWidth()-p.sizeDiff.width,j=i.outerHeight()-p.sizeDiff.height;if(p._helper&&!f.animate&&(/relative/).test(g.css("position"))){c(this).css({left:q.left-d.left-l.left,width:n,height:j})}if(p._helper&&!f.animate&&(/static/).test(g.css("position"))){c(this).css({left:q.left-d.left-l.left,width:n,height:j})}}});c.ui.plugin.add("resizable","ghost",{start:function(f,g){var d=c(this).data("resizable"),h=d.options,e=d.size;d.ghost=d.originalElement.clone();d.ghost.css({opacity:0.25,display:"block",position:"relative",height:e.height,width:e.width,margin:0,left:0,top:0}).addClass("ui-resizable-ghost").addClass(typeof h.ghost=="string"?h.ghost:"");d.ghost.appendTo(d.helper)},resize:function(e,f){var d=c(this).data("resizable"),g=d.options;if(d.ghost){d.ghost.css({position:"relative",height:d.size.height,width:d.size.width})}},stop:function(e,f){var d=c(this).data("resizable"),g=d.options;if(d.ghost&&d.helper){d.helper.get(0).removeChild(d.ghost.get(0))}}});c.ui.plugin.add("resizable","grid",{resize:function(d,l){var n=c(this).data("resizable"),g=n.options,j=n.size,h=n.originalSize,i=n.originalPosition,m=n.axis,k=g._aspectRatio||d.shiftKey;g.grid=typeof g.grid=="number"?[g.grid,g.grid]:g.grid;var f=Math.round((j.width-h.width)/(g.grid[0]||1))*(g.grid[0]||1),e=Math.round((j.height-h.height)/(g.grid[1]||1))*(g.grid[1]||1);if(/^(se|s|e)$/.test(m)){n.size.width=h.width+f;n.size.height=h.height+e}else{if(/^(ne)$/.test(m)){n.size.width=h.width+f;n.size.height=h.height+e;n.position.top=i.top-e}else{if(/^(sw)$/.test(m)){n.size.width=h.width+f;n.size.height=h.height+e;n.position.left=i.left-f}else{n.size.width=h.width+f;n.size.height=h.height+e;n.position.top=i.top-e;n.position.left=i.left-f}}}}});var b=function(d){return parseInt(d,10)||0};var a=function(d){return !isNaN(parseInt(d,10))}})(jQuery);;/* - * jQuery UI Selectable 1.7.2 - * - * Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT (MIT-LICENSE.txt) - * and GPL (GPL-LICENSE.txt) licenses. - * - * http://docs.jquery.com/UI/Selectables - * - * Depends: - * ui.core.js - */ -(function(a){a.widget("ui.selectable",a.extend({},a.ui.mouse,{_init:function(){var b=this;this.element.addClass("ui-selectable");this.dragged=false;var c;this.refresh=function(){c=a(b.options.filter,b.element[0]);c.each(function(){var d=a(this);var e=d.offset();a.data(this,"selectable-item",{element:this,$element:d,left:e.left,top:e.top,right:e.left+d.outerWidth(),bottom:e.top+d.outerHeight(),startselected:false,selected:d.hasClass("ui-selected"),selecting:d.hasClass("ui-selecting"),unselecting:d.hasClass("ui-unselecting")})})};this.refresh();this.selectees=c.addClass("ui-selectee");this._mouseInit();this.helper=a(document.createElement("div")).css({border:"1px dotted black"}).addClass("ui-selectable-helper")},destroy:function(){this.element.removeClass("ui-selectable ui-selectable-disabled").removeData("selectable").unbind(".selectable");this._mouseDestroy()},_mouseStart:function(d){var b=this;this.opos=[d.pageX,d.pageY];if(this.options.disabled){return}var c=this.options;this.selectees=a(c.filter,this.element[0]);this._trigger("start",d);a(c.appendTo).append(this.helper);this.helper.css({"z-index":100,position:"absolute",left:d.clientX,top:d.clientY,width:0,height:0});if(c.autoRefresh){this.refresh()}this.selectees.filter(".ui-selected").each(function(){var e=a.data(this,"selectable-item");e.startselected=true;if(!d.metaKey){e.$element.removeClass("ui-selected");e.selected=false;e.$element.addClass("ui-unselecting");e.unselecting=true;b._trigger("unselecting",d,{unselecting:e.element})}});a(d.target).parents().andSelf().each(function(){var e=a.data(this,"selectable-item");if(e){e.$element.removeClass("ui-unselecting").addClass("ui-selecting");e.unselecting=false;e.selecting=true;e.selected=true;b._trigger("selecting",d,{selecting:e.element});return false}})},_mouseDrag:function(i){var c=this;this.dragged=true;if(this.options.disabled){return}var e=this.options;var d=this.opos[0],h=this.opos[1],b=i.pageX,g=i.pageY;if(d>b){var f=b;b=d;d=f}if(h>g){var f=g;g=h;h=f}this.helper.css({left:d,top:h,width:b-d,height:g-h});this.selectees.each(function(){var j=a.data(this,"selectable-item");if(!j||j.element==c.element[0]){return}var k=false;if(e.tolerance=="touch"){k=(!(j.left>b||j.rightg||j.bottomd&&j.righth&&j.bottom=0&&this.anchors[d.selected])||d.selected<0)?d.selected:0;d.disabled=a.unique(d.disabled.concat(a.map(this.lis.filter(".ui-state-disabled"),function(q,o){return p.lis.index(q)}))).sort();if(a.inArray(d.selected,d.disabled)!=-1){d.disabled.splice(a.inArray(d.selected,d.disabled),1)}this.panels.addClass("ui-tabs-hide");this.lis.removeClass("ui-tabs-selected ui-state-active");if(d.selected>=0&&this.anchors.length){this.panels.eq(d.selected).removeClass("ui-tabs-hide");this.lis.eq(d.selected).addClass("ui-tabs-selected ui-state-active");p.element.queue("tabs",function(){p._trigger("show",null,p._ui(p.anchors[d.selected],p.panels[d.selected]))});this.load(d.selected)}a(window).bind("unload",function(){p.lis.add(p.anchors).unbind(".tabs");p.lis=p.anchors=p.panels=null})}else{d.selected=this.lis.index(this.lis.filter(".ui-tabs-selected"))}this.element[d.collapsible?"addClass":"removeClass"]("ui-tabs-collapsible");if(d.cookie){this._cookie(d.selected,d.cookie)}for(var g=0,m;(m=this.lis[g]);g++){a(m)[a.inArray(g,d.disabled)!=-1&&!a(m).hasClass("ui-tabs-selected")?"addClass":"removeClass"]("ui-state-disabled")}if(d.cache===false){this.anchors.removeData("cache.tabs")}this.lis.add(this.anchors).unbind(".tabs");if(d.event!="mouseover"){var f=function(o,i){if(i.is(":not(.ui-state-disabled)")){i.addClass("ui-state-"+o)}};var j=function(o,i){i.removeClass("ui-state-"+o)};this.lis.bind("mouseover.tabs",function(){f("hover",a(this))});this.lis.bind("mouseout.tabs",function(){j("hover",a(this))});this.anchors.bind("focus.tabs",function(){f("focus",a(this).closest("li"))});this.anchors.bind("blur.tabs",function(){j("focus",a(this).closest("li"))})}var b,h;if(d.fx){if(a.isArray(d.fx)){b=d.fx[0];h=d.fx[1]}else{b=h=d.fx}}function e(i,o){i.css({display:""});if(a.browser.msie&&o.opacity){i[0].style.removeAttribute("filter")}}var k=h?function(i,o){a(i).closest("li").removeClass("ui-state-default").addClass("ui-tabs-selected ui-state-active");o.hide().removeClass("ui-tabs-hide").animate(h,h.duration||"normal",function(){e(o,h);p._trigger("show",null,p._ui(i,o[0]))})}:function(i,o){a(i).closest("li").removeClass("ui-state-default").addClass("ui-tabs-selected ui-state-active");o.removeClass("ui-tabs-hide");p._trigger("show",null,p._ui(i,o[0]))};var l=b?function(o,i){i.animate(b,b.duration||"normal",function(){p.lis.removeClass("ui-tabs-selected ui-state-active").addClass("ui-state-default");i.addClass("ui-tabs-hide");e(i,b);p.element.dequeue("tabs")})}:function(o,i,q){p.lis.removeClass("ui-tabs-selected ui-state-active").addClass("ui-state-default");i.addClass("ui-tabs-hide");p.element.dequeue("tabs")};this.anchors.bind(d.event+".tabs",function(){var o=this,r=a(this).closest("li"),i=p.panels.filter(":not(.ui-tabs-hide)"),q=a(p._sanitizeSelector(this.hash));if((r.hasClass("ui-tabs-selected")&&!d.collapsible)||r.hasClass("ui-state-disabled")||r.hasClass("ui-state-processing")||p._trigger("select",null,p._ui(this,q[0]))===false){this.blur();return false}d.selected=p.anchors.index(this);p.abort();if(d.collapsible){if(r.hasClass("ui-tabs-selected")){d.selected=-1;if(d.cookie){p._cookie(d.selected,d.cookie)}p.element.queue("tabs",function(){l(o,i)}).dequeue("tabs");this.blur();return false}else{if(!i.length){if(d.cookie){p._cookie(d.selected,d.cookie)}p.element.queue("tabs",function(){k(o,q)});p.load(p.anchors.index(this));this.blur();return false}}}if(d.cookie){p._cookie(d.selected,d.cookie)}if(q.length){if(i.length){p.element.queue("tabs",function(){l(o,i)})}p.element.queue("tabs",function(){k(o,q)});p.load(p.anchors.index(this))}else{throw"jQuery UI Tabs: Mismatching fragment identifier."}if(a.browser.msie){this.blur()}});this.anchors.bind("click.tabs",function(){return false})},destroy:function(){var b=this.options;this.abort();this.element.unbind(".tabs").removeClass("ui-tabs ui-widget ui-widget-content ui-corner-all ui-tabs-collapsible").removeData("tabs");this.list.removeClass("ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all");this.anchors.each(function(){var c=a.data(this,"href.tabs");if(c){this.href=c}var d=a(this).unbind(".tabs");a.each(["href","load","cache"],function(e,f){d.removeData(f+".tabs")})});this.lis.unbind(".tabs").add(this.panels).each(function(){if(a.data(this,"destroy.tabs")){a(this).remove()}else{a(this).removeClass(["ui-state-default","ui-corner-top","ui-tabs-selected","ui-state-active","ui-state-hover","ui-state-focus","ui-state-disabled","ui-tabs-panel","ui-widget-content","ui-corner-bottom","ui-tabs-hide"].join(" "))}});if(b.cookie){this._cookie(null,b.cookie)}},add:function(e,d,c){if(c===undefined){c=this.anchors.length}var b=this,g=this.options,i=a(g.tabTemplate.replace(/#\{href\}/g,e).replace(/#\{label\}/g,d)),h=!e.indexOf("#")?e.replace("#",""):this._tabId(a("a",i)[0]);i.addClass("ui-state-default ui-corner-top").data("destroy.tabs",true);var f=a("#"+h);if(!f.length){f=a(g.panelTemplate).attr("id",h).data("destroy.tabs",true)}f.addClass("ui-tabs-panel ui-widget-content ui-corner-bottom ui-tabs-hide");if(c>=this.lis.length){i.appendTo(this.list);f.appendTo(this.list[0].parentNode)}else{i.insertBefore(this.lis[c]);f.insertBefore(this.panels[c])}g.disabled=a.map(g.disabled,function(k,j){return k>=c?++k:k});this._tabify();if(this.anchors.length==1){i.addClass("ui-tabs-selected ui-state-active");f.removeClass("ui-tabs-hide");this.element.queue("tabs",function(){b._trigger("show",null,b._ui(b.anchors[0],b.panels[0]))});this.load(0)}this._trigger("add",null,this._ui(this.anchors[c],this.panels[c]))},remove:function(b){var d=this.options,e=this.lis.eq(b).remove(),c=this.panels.eq(b).remove();if(e.hasClass("ui-tabs-selected")&&this.anchors.length>1){this.select(b+(b+1=b?--g:g});this._tabify();this._trigger("remove",null,this._ui(e.find("a")[0],c[0]))},enable:function(b){var c=this.options;if(a.inArray(b,c.disabled)==-1){return}this.lis.eq(b).removeClass("ui-state-disabled");c.disabled=a.grep(c.disabled,function(e,d){return e!=b});this._trigger("enable",null,this._ui(this.anchors[b],this.panels[b]))},disable:function(c){var b=this,d=this.options;if(c!=d.selected){this.lis.eq(c).addClass("ui-state-disabled");d.disabled.push(c);d.disabled.sort();this._trigger("disable",null,this._ui(this.anchors[c],this.panels[c]))}},select:function(b){if(typeof b=="string"){b=this.anchors.index(this.anchors.filter("[href$="+b+"]"))}else{if(b===null){b=-1}}if(b==-1&&this.options.collapsible){b=this.options.selected}this.anchors.eq(b).trigger(this.options.event+".tabs")},load:function(e){var c=this,g=this.options,b=this.anchors.eq(e)[0],d=a.data(b,"load.tabs");this.abort();if(!d||this.element.queue("tabs").length!==0&&a.data(b,"cache.tabs")){this.element.dequeue("tabs");return}this.lis.eq(e).addClass("ui-state-processing");if(g.spinner){var f=a("span",b);f.data("label.tabs",f.html()).html(g.spinner)}this.xhr=a.ajax(a.extend({},g.ajaxOptions,{url:d,success:function(i,h){a(c._sanitizeSelector(b.hash)).html(i);c._cleanup();if(g.cache){a.data(b,"cache.tabs",true)}c._trigger("load",null,c._ui(c.anchors[e],c.panels[e]));try{g.ajaxOptions.success(i,h)}catch(j){}c.element.dequeue("tabs")}}))},abort:function(){this.element.queue([]);this.panels.stop(false,true);if(this.xhr){this.xhr.abort();delete this.xhr}this._cleanup()},url:function(c,b){this.anchors.eq(c).removeData("cache.tabs").data("load.tabs",b)},length:function(){return this.anchors.length}});a.extend(a.ui.tabs,{version:"1.7.2",getter:"length",defaults:{ajaxOptions:null,cache:false,cookie:null,collapsible:false,disabled:[],event:"click",fx:null,idPrefix:"ui-tabs-",panelTemplate:"
                          ",spinner:"Loading…",tabTemplate:'
                        • #{label}
                        • '}});a.extend(a.ui.tabs.prototype,{rotation:null,rotate:function(d,f){var b=this,g=this.options;var c=b._rotate||(b._rotate=function(h){clearTimeout(b.rotation);b.rotation=setTimeout(function(){var i=g.selected;b.select(++i
                          ')}$.extend(Datepicker.prototype,{markerClassName:"hasDatepicker",log:function(){if(this.debug){console.log.apply("",arguments)}},setDefaults:function(settings){extendRemove(this._defaults,settings||{});return this},_attachDatepicker:function(target,settings){var inlineSettings=null;for(var attrName in this._defaults){var attrValue=target.getAttribute("date:"+attrName);if(attrValue){inlineSettings=inlineSettings||{};try{inlineSettings[attrName]=eval(attrValue)}catch(err){inlineSettings[attrName]=attrValue}}}var nodeName=target.nodeName.toLowerCase();var inline=(nodeName=="div"||nodeName=="span");if(!target.id){target.id="dp"+(++this.uuid)}var inst=this._newInst($(target),inline);inst.settings=$.extend({},settings||{},inlineSettings||{});if(nodeName=="input"){this._connectDatepicker(target,inst)}else{if(inline){this._inlineDatepicker(target,inst)}}},_newInst:function(target,inline){var id=target[0].id.replace(/([:\[\]\.])/g,"\\\\$1");return{id:id,input:target,selectedDay:0,selectedMonth:0,selectedYear:0,drawMonth:0,drawYear:0,inline:inline,dpDiv:(!inline?this.dpDiv:$('
                          '))}},_connectDatepicker:function(target,inst){var input=$(target);inst.append=$([]);inst.trigger=$([]);if(input.hasClass(this.markerClassName)){return}var appendText=this._get(inst,"appendText");var isRTL=this._get(inst,"isRTL");if(appendText){inst.append=$(''+appendText+"");input[isRTL?"before":"after"](inst.append)}var showOn=this._get(inst,"showOn");if(showOn=="focus"||showOn=="both"){input.focus(this._showDatepicker)}if(showOn=="button"||showOn=="both"){var buttonText=this._get(inst,"buttonText");var buttonImage=this._get(inst,"buttonImage");inst.trigger=$(this._get(inst,"buttonImageOnly")?$("").addClass(this._triggerClass).attr({src:buttonImage,alt:buttonText,title:buttonText}):$('').addClass(this._triggerClass).html(buttonImage==""?buttonText:$("").attr({src:buttonImage,alt:buttonText,title:buttonText})));input[isRTL?"before":"after"](inst.trigger);inst.trigger.click(function(){if($.datepicker._datepickerShowing&&$.datepicker._lastInput==target){$.datepicker._hideDatepicker()}else{$.datepicker._showDatepicker(target)}return false})}input.addClass(this.markerClassName).keydown(this._doKeyDown).keypress(this._doKeyPress).bind("setData.datepicker",function(event,key,value){inst.settings[key]=value}).bind("getData.datepicker",function(event,key){return this._get(inst,key)});$.data(target,PROP_NAME,inst)},_inlineDatepicker:function(target,inst){var divSpan=$(target);if(divSpan.hasClass(this.markerClassName)){return}divSpan.addClass(this.markerClassName).append(inst.dpDiv).bind("setData.datepicker",function(event,key,value){inst.settings[key]=value}).bind("getData.datepicker",function(event,key){return this._get(inst,key)});$.data(target,PROP_NAME,inst);this._setDate(inst,this._getDefaultDate(inst));this._updateDatepicker(inst);this._updateAlternate(inst)},_dialogDatepicker:function(input,dateText,onSelect,settings,pos){var inst=this._dialogInst;if(!inst){var id="dp"+(++this.uuid);this._dialogInput=$('');this._dialogInput.keydown(this._doKeyDown);$("body").append(this._dialogInput);inst=this._dialogInst=this._newInst(this._dialogInput,false);inst.settings={};$.data(this._dialogInput[0],PROP_NAME,inst)}extendRemove(inst.settings,settings||{});this._dialogInput.val(dateText);this._pos=(pos?(pos.length?pos:[pos.pageX,pos.pageY]):null);if(!this._pos){var browserWidth=window.innerWidth||document.documentElement.clientWidth||document.body.clientWidth;var browserHeight=window.innerHeight||document.documentElement.clientHeight||document.body.clientHeight;var scrollX=document.documentElement.scrollLeft||document.body.scrollLeft;var scrollY=document.documentElement.scrollTop||document.body.scrollTop;this._pos=[(browserWidth/2)-100+scrollX,(browserHeight/2)-150+scrollY]}this._dialogInput.css("left",this._pos[0]+"px").css("top",this._pos[1]+"px");inst.settings.onSelect=onSelect;this._inDialog=true;this.dpDiv.addClass(this._dialogClass);this._showDatepicker(this._dialogInput[0]);if($.blockUI){$.blockUI(this.dpDiv)}$.data(this._dialogInput[0],PROP_NAME,inst);return this},_destroyDatepicker:function(target){var $target=$(target);var inst=$.data(target,PROP_NAME);if(!$target.hasClass(this.markerClassName)){return}var nodeName=target.nodeName.toLowerCase();$.removeData(target,PROP_NAME);if(nodeName=="input"){inst.append.remove();inst.trigger.remove();$target.removeClass(this.markerClassName).unbind("focus",this._showDatepicker).unbind("keydown",this._doKeyDown).unbind("keypress",this._doKeyPress)}else{if(nodeName=="div"||nodeName=="span"){$target.removeClass(this.markerClassName).empty()}}},_enableDatepicker:function(target){var $target=$(target);var inst=$.data(target,PROP_NAME);if(!$target.hasClass(this.markerClassName)){return}var nodeName=target.nodeName.toLowerCase();if(nodeName=="input"){target.disabled=false;inst.trigger.filter("button").each(function(){this.disabled=false}).end().filter("img").css({opacity:"1.0",cursor:""})}else{if(nodeName=="div"||nodeName=="span"){var inline=$target.children("."+this._inlineClass);inline.children().removeClass("ui-state-disabled")}}this._disabledInputs=$.map(this._disabledInputs,function(value){return(value==target?null:value)})},_disableDatepicker:function(target){var $target=$(target);var inst=$.data(target,PROP_NAME);if(!$target.hasClass(this.markerClassName)){return}var nodeName=target.nodeName.toLowerCase();if(nodeName=="input"){target.disabled=true;inst.trigger.filter("button").each(function(){this.disabled=true}).end().filter("img").css({opacity:"0.5",cursor:"default"})}else{if(nodeName=="div"||nodeName=="span"){var inline=$target.children("."+this._inlineClass);inline.children().addClass("ui-state-disabled")}}this._disabledInputs=$.map(this._disabledInputs,function(value){return(value==target?null:value)});this._disabledInputs[this._disabledInputs.length]=target},_isDisabledDatepicker:function(target){if(!target){return false}for(var i=0;i-1)}},_showDatepicker:function(input){input=input.target||input;if(input.nodeName.toLowerCase()!="input"){input=$("input",input.parentNode)[0]}if($.datepicker._isDisabledDatepicker(input)||$.datepicker._lastInput==input){return}var inst=$.datepicker._getInst(input);var beforeShow=$.datepicker._get(inst,"beforeShow");extendRemove(inst.settings,(beforeShow?beforeShow.apply(input,[input,inst]):{}));$.datepicker._hideDatepicker(null,"");$.datepicker._lastInput=input;$.datepicker._setDateFromField(inst);if($.datepicker._inDialog){input.value=""}if(!$.datepicker._pos){$.datepicker._pos=$.datepicker._findPos(input);$.datepicker._pos[1]+=input.offsetHeight}var isFixed=false;$(input).parents().each(function(){isFixed|=$(this).css("position")=="fixed";return !isFixed});if(isFixed&&$.browser.opera){$.datepicker._pos[0]-=document.documentElement.scrollLeft;$.datepicker._pos[1]-=document.documentElement.scrollTop}var offset={left:$.datepicker._pos[0],top:$.datepicker._pos[1]};$.datepicker._pos=null;inst.rangeStart=null;inst.dpDiv.css({position:"absolute",display:"block",top:"-1000px"});$.datepicker._updateDatepicker(inst);offset=$.datepicker._checkOffset(inst,offset,isFixed);inst.dpDiv.css({position:($.datepicker._inDialog&&$.blockUI?"static":(isFixed?"fixed":"absolute")),display:"none",left:offset.left+"px",top:offset.top+"px"});if(!inst.inline){var showAnim=$.datepicker._get(inst,"showAnim")||"show";var duration=$.datepicker._get(inst,"duration");var postProcess=function(){$.datepicker._datepickerShowing=true;if($.browser.msie&&parseInt($.browser.version,10)<7){$("iframe.ui-datepicker-cover").css({width:inst.dpDiv.width()+4,height:inst.dpDiv.height()+4})}};if($.effects&&$.effects[showAnim]){inst.dpDiv.show(showAnim,$.datepicker._get(inst,"showOptions"),duration,postProcess)}else{inst.dpDiv[showAnim](duration,postProcess)}if(duration==""){postProcess()}if(inst.input[0].type!="hidden"){inst.input[0].focus()}$.datepicker._curInst=inst}},_updateDatepicker:function(inst){var dims={width:inst.dpDiv.width()+4,height:inst.dpDiv.height()+4};var self=this;inst.dpDiv.empty().append(this._generateHTML(inst)).find("iframe.ui-datepicker-cover").css({width:dims.width,height:dims.height}).end().find("button, .ui-datepicker-prev, .ui-datepicker-next, .ui-datepicker-calendar td a").bind("mouseout",function(){$(this).removeClass("ui-state-hover");if(this.className.indexOf("ui-datepicker-prev")!=-1){$(this).removeClass("ui-datepicker-prev-hover")}if(this.className.indexOf("ui-datepicker-next")!=-1){$(this).removeClass("ui-datepicker-next-hover")}}).bind("mouseover",function(){if(!self._isDisabledDatepicker(inst.inline?inst.dpDiv.parent()[0]:inst.input[0])){$(this).parents(".ui-datepicker-calendar").find("a").removeClass("ui-state-hover");$(this).addClass("ui-state-hover");if(this.className.indexOf("ui-datepicker-prev")!=-1){$(this).addClass("ui-datepicker-prev-hover")}if(this.className.indexOf("ui-datepicker-next")!=-1){$(this).addClass("ui-datepicker-next-hover")}}}).end().find("."+this._dayOverClass+" a").trigger("mouseover").end();var numMonths=this._getNumberOfMonths(inst);var cols=numMonths[1];var width=17;if(cols>1){inst.dpDiv.addClass("ui-datepicker-multi-"+cols).css("width",(width*cols)+"em")}else{inst.dpDiv.removeClass("ui-datepicker-multi-2 ui-datepicker-multi-3 ui-datepicker-multi-4").width("")}inst.dpDiv[(numMonths[0]!=1||numMonths[1]!=1?"add":"remove")+"Class"]("ui-datepicker-multi");inst.dpDiv[(this._get(inst,"isRTL")?"add":"remove")+"Class"]("ui-datepicker-rtl");if(inst.input&&inst.input[0].type!="hidden"&&inst==$.datepicker._curInst){$(inst.input[0]).focus()}},_checkOffset:function(inst,offset,isFixed){var dpWidth=inst.dpDiv.outerWidth();var dpHeight=inst.dpDiv.outerHeight();var inputWidth=inst.input?inst.input.outerWidth():0;var inputHeight=inst.input?inst.input.outerHeight():0;var viewWidth=(window.innerWidth||document.documentElement.clientWidth||document.body.clientWidth)+$(document).scrollLeft();var viewHeight=(window.innerHeight||document.documentElement.clientHeight||document.body.clientHeight)+$(document).scrollTop();offset.left-=(this._get(inst,"isRTL")?(dpWidth-inputWidth):0);offset.left-=(isFixed&&offset.left==inst.input.offset().left)?$(document).scrollLeft():0;offset.top-=(isFixed&&offset.top==(inst.input.offset().top+inputHeight))?$(document).scrollTop():0;offset.left-=(offset.left+dpWidth>viewWidth&&viewWidth>dpWidth)?Math.abs(offset.left+dpWidth-viewWidth):0;offset.top-=(offset.top+dpHeight>viewHeight&&viewHeight>dpHeight)?Math.abs(offset.top+dpHeight+inputHeight*2-viewHeight):0;return offset},_findPos:function(obj){while(obj&&(obj.type=="hidden"||obj.nodeType!=1)){obj=obj.nextSibling}var position=$(obj).offset();return[position.left,position.top]},_hideDatepicker:function(input,duration){var inst=this._curInst;if(!inst||(input&&inst!=$.data(input,PROP_NAME))){return}if(inst.stayOpen){this._selectDate("#"+inst.id,this._formatDate(inst,inst.currentDay,inst.currentMonth,inst.currentYear))}inst.stayOpen=false;if(this._datepickerShowing){duration=(duration!=null?duration:this._get(inst,"duration"));var showAnim=this._get(inst,"showAnim");var postProcess=function(){$.datepicker._tidyDialog(inst)};if(duration!=""&&$.effects&&$.effects[showAnim]){inst.dpDiv.hide(showAnim,$.datepicker._get(inst,"showOptions"),duration,postProcess)}else{inst.dpDiv[(duration==""?"hide":(showAnim=="slideDown"?"slideUp":(showAnim=="fadeIn"?"fadeOut":"hide")))](duration,postProcess)}if(duration==""){this._tidyDialog(inst)}var onClose=this._get(inst,"onClose");if(onClose){onClose.apply((inst.input?inst.input[0]:null),[(inst.input?inst.input.val():""),inst])}this._datepickerShowing=false;this._lastInput=null;if(this._inDialog){this._dialogInput.css({position:"absolute",left:"0",top:"-100px"});if($.blockUI){$.unblockUI();$("body").append(this.dpDiv)}}this._inDialog=false}this._curInst=null},_tidyDialog:function(inst){inst.dpDiv.removeClass(this._dialogClass).unbind(".ui-datepicker-calendar")},_checkExternalClick:function(event){if(!$.datepicker._curInst){return}var $target=$(event.target);if(($target.parents("#"+$.datepicker._mainDivId).length==0)&&!$target.hasClass($.datepicker.markerClassName)&&!$target.hasClass($.datepicker._triggerClass)&&$.datepicker._datepickerShowing&&!($.datepicker._inDialog&&$.blockUI)){$.datepicker._hideDatepicker(null,"")}},_adjustDate:function(id,offset,period){var target=$(id);var inst=this._getInst(target[0]);if(this._isDisabledDatepicker(target[0])){return}this._adjustInstDate(inst,offset+(period=="M"?this._get(inst,"showCurrentAtPos"):0),period);this._updateDatepicker(inst)},_gotoToday:function(id){var target=$(id);var inst=this._getInst(target[0]);if(this._get(inst,"gotoCurrent")&&inst.currentDay){inst.selectedDay=inst.currentDay;inst.drawMonth=inst.selectedMonth=inst.currentMonth;inst.drawYear=inst.selectedYear=inst.currentYear}else{var date=new Date();inst.selectedDay=date.getDate();inst.drawMonth=inst.selectedMonth=date.getMonth();inst.drawYear=inst.selectedYear=date.getFullYear()}this._notifyChange(inst);this._adjustDate(target)},_selectMonthYear:function(id,select,period){var target=$(id);var inst=this._getInst(target[0]);inst._selectingMonthYear=false;inst["selected"+(period=="M"?"Month":"Year")]=inst["draw"+(period=="M"?"Month":"Year")]=parseInt(select.options[select.selectedIndex].value,10);this._notifyChange(inst);this._adjustDate(target)},_clickMonthYear:function(id){var target=$(id);var inst=this._getInst(target[0]);if(inst.input&&inst._selectingMonthYear&&!$.browser.msie){inst.input[0].focus()}inst._selectingMonthYear=!inst._selectingMonthYear},_selectDay:function(id,month,year,td){var target=$(id);if($(td).hasClass(this._unselectableClass)||this._isDisabledDatepicker(target[0])){return}var inst=this._getInst(target[0]);inst.selectedDay=inst.currentDay=$("a",td).html();inst.selectedMonth=inst.currentMonth=month;inst.selectedYear=inst.currentYear=year;if(inst.stayOpen){inst.endDay=inst.endMonth=inst.endYear=null}this._selectDate(id,this._formatDate(inst,inst.currentDay,inst.currentMonth,inst.currentYear));if(inst.stayOpen){inst.rangeStart=this._daylightSavingAdjust(new Date(inst.currentYear,inst.currentMonth,inst.currentDay));this._updateDatepicker(inst)}},_clearDate:function(id){var target=$(id);var inst=this._getInst(target[0]);inst.stayOpen=false;inst.endDay=inst.endMonth=inst.endYear=inst.rangeStart=null;this._selectDate(target,"")},_selectDate:function(id,dateStr){var target=$(id);var inst=this._getInst(target[0]);dateStr=(dateStr!=null?dateStr:this._formatDate(inst));if(inst.input){inst.input.val(dateStr)}this._updateAlternate(inst);var onSelect=this._get(inst,"onSelect");if(onSelect){onSelect.apply((inst.input?inst.input[0]:null),[dateStr,inst])}else{if(inst.input){inst.input.trigger("change")}}if(inst.inline){this._updateDatepicker(inst)}else{if(!inst.stayOpen){this._hideDatepicker(null,this._get(inst,"duration"));this._lastInput=inst.input[0];if(typeof(inst.input[0])!="object"){inst.input[0].focus()}this._lastInput=null}}},_updateAlternate:function(inst){var altField=this._get(inst,"altField");if(altField){var altFormat=this._get(inst,"altFormat")||this._get(inst,"dateFormat");var date=this._getDate(inst);dateStr=this.formatDate(altFormat,date,this._getFormatConfig(inst));$(altField).each(function(){$(this).val(dateStr)})}},noWeekends:function(date){var day=date.getDay();return[(day>0&&day<6),""]},iso8601Week:function(date){var checkDate=new Date(date.getFullYear(),date.getMonth(),date.getDate());var firstMon=new Date(checkDate.getFullYear(),1-1,4);var firstDay=firstMon.getDay()||7;firstMon.setDate(firstMon.getDate()+1-firstDay);if(firstDay<4&&checkDatenew Date(checkDate.getFullYear(),12-1,28)){firstDay=new Date(checkDate.getFullYear()+1,1-1,4).getDay()||7;if(firstDay>4&&(checkDate.getDay()||7)0&&iValue="0"&&value.charAt(iValue)<="9"){num=num*10+parseInt(value.charAt(iValue++),10);size--}if(size==origSize){throw"Missing number at position "+iValue}return num};var getName=function(match,shortNames,longNames){var names=(lookAhead(match)?longNames:shortNames);var size=0;for(var j=0;j0&&iValue-1){month=1;day=doy;do{var dim=this._getDaysInMonth(year,month-1);if(day<=dim){break}month++;day-=dim}while(true)}var date=this._daylightSavingAdjust(new Date(year,month-1,day));if(date.getFullYear()!=year||date.getMonth()+1!=month||date.getDate()!=day){throw"Invalid date"}return date},ATOM:"yy-mm-dd",COOKIE:"D, dd M yy",ISO_8601:"yy-mm-dd",RFC_822:"D, d M y",RFC_850:"DD, dd-M-y",RFC_1036:"D, d M y",RFC_1123:"D, d M yy",RFC_2822:"D, d M yy",RSS:"D, d M y",TIMESTAMP:"@",W3C:"yy-mm-dd",formatDate:function(format,date,settings){if(!date){return""}var dayNamesShort=(settings?settings.dayNamesShort:null)||this._defaults.dayNamesShort;var dayNames=(settings?settings.dayNames:null)||this._defaults.dayNames;var monthNamesShort=(settings?settings.monthNamesShort:null)||this._defaults.monthNamesShort;var monthNames=(settings?settings.monthNames:null)||this._defaults.monthNames;var lookAhead=function(match){var matches=(iFormat+1=0;m--){doy+=this._getDaysInMonth(date.getFullYear(),m)}output+=formatNumber("o",doy,3);break;case"m":output+=formatNumber("m",date.getMonth()+1,2);break;case"M":output+=formatName("M",date.getMonth(),monthNamesShort,monthNames);break;case"y":output+=(lookAhead("y")?date.getFullYear():(date.getYear()%100<10?"0":"")+date.getYear()%100);break;case"@":output+=date.getTime();break;case"'":if(lookAhead("'")){output+="'"}else{literal=true}break;default:output+=format.charAt(iFormat)}}}}return output},_possibleChars:function(format){var chars="";var literal=false;for(var iFormat=0;iFormatmaxDate?maxDate:date);return date},_determineDate:function(date,defaultDate){var offsetNumeric=function(offset){var date=new Date();date.setDate(date.getDate()+offset);return date};var offsetString=function(offset,getDaysInMonth){var date=new Date();var year=date.getFullYear();var month=date.getMonth();var day=date.getDate();var pattern=/([+-]?[0-9]+)\s*(d|D|w|W|m|M|y|Y)?/g;var matches=pattern.exec(offset);while(matches){switch(matches[2]||"d"){case"d":case"D":day+=parseInt(matches[1],10);break;case"w":case"W":day+=parseInt(matches[1],10)*7;break;case"m":case"M":month+=parseInt(matches[1],10);day=Math.min(day,getDaysInMonth(year,month));break;case"y":case"Y":year+=parseInt(matches[1],10);day=Math.min(day,getDaysInMonth(year,month));break}matches=pattern.exec(offset)}return new Date(year,month,day)};date=(date==null?defaultDate:(typeof date=="string"?offsetString(date,this._getDaysInMonth):(typeof date=="number"?(isNaN(date)?defaultDate:offsetNumeric(date)):date)));date=(date&&date.toString()=="Invalid Date"?defaultDate:date);if(date){date.setHours(0);date.setMinutes(0);date.setSeconds(0);date.setMilliseconds(0)}return this._daylightSavingAdjust(date)},_daylightSavingAdjust:function(date){if(!date){return null}date.setHours(date.getHours()>12?date.getHours()+2:0);return date},_setDate:function(inst,date,endDate){var clear=!(date);var origMonth=inst.selectedMonth;var origYear=inst.selectedYear;date=this._determineDate(date,new Date());inst.selectedDay=inst.currentDay=date.getDate();inst.drawMonth=inst.selectedMonth=inst.currentMonth=date.getMonth();inst.drawYear=inst.selectedYear=inst.currentYear=date.getFullYear();if(origMonth!=inst.selectedMonth||origYear!=inst.selectedYear){this._notifyChange(inst)}this._adjustInstDate(inst);if(inst.input){inst.input.val(clear?"":this._formatDate(inst))}},_getDate:function(inst){var startDate=(!inst.currentYear||(inst.input&&inst.input.val()=="")?null:this._daylightSavingAdjust(new Date(inst.currentYear,inst.currentMonth,inst.currentDay)));return startDate},_generateHTML:function(inst){var today=new Date();today=this._daylightSavingAdjust(new Date(today.getFullYear(),today.getMonth(),today.getDate()));var isRTL=this._get(inst,"isRTL");var showButtonPanel=this._get(inst,"showButtonPanel");var hideIfNoPrevNext=this._get(inst,"hideIfNoPrevNext");var navigationAsDateFormat=this._get(inst,"navigationAsDateFormat");var numMonths=this._getNumberOfMonths(inst);var showCurrentAtPos=this._get(inst,"showCurrentAtPos");var stepMonths=this._get(inst,"stepMonths");var stepBigMonths=this._get(inst,"stepBigMonths");var isMultiMonth=(numMonths[0]!=1||numMonths[1]!=1);var currentDate=this._daylightSavingAdjust((!inst.currentDay?new Date(9999,9,9):new Date(inst.currentYear,inst.currentMonth,inst.currentDay)));var minDate=this._getMinMaxDate(inst,"min",true);var maxDate=this._getMinMaxDate(inst,"max");var drawMonth=inst.drawMonth-showCurrentAtPos;var drawYear=inst.drawYear;if(drawMonth<0){drawMonth+=12;drawYear--}if(maxDate){var maxDraw=this._daylightSavingAdjust(new Date(maxDate.getFullYear(),maxDate.getMonth()-numMonths[1]+1,maxDate.getDate()));maxDraw=(minDate&&maxDrawmaxDraw){drawMonth--;if(drawMonth<0){drawMonth=11;drawYear--}}}inst.drawMonth=drawMonth;inst.drawYear=drawYear;var prevText=this._get(inst,"prevText");prevText=(!navigationAsDateFormat?prevText:this.formatDate(prevText,this._daylightSavingAdjust(new Date(drawYear,drawMonth-stepMonths,1)),this._getFormatConfig(inst)));var prev=(this._canAdjustMonth(inst,-1,drawYear,drawMonth)?''+prevText+"":(hideIfNoPrevNext?"":''+prevText+""));var nextText=this._get(inst,"nextText");nextText=(!navigationAsDateFormat?nextText:this.formatDate(nextText,this._daylightSavingAdjust(new Date(drawYear,drawMonth+stepMonths,1)),this._getFormatConfig(inst)));var next=(this._canAdjustMonth(inst,+1,drawYear,drawMonth)?''+nextText+"":(hideIfNoPrevNext?"":''+nextText+""));var currentText=this._get(inst,"currentText");var gotoDate=(this._get(inst,"gotoCurrent")&&inst.currentDay?currentDate:today);currentText=(!navigationAsDateFormat?currentText:this.formatDate(currentText,gotoDate,this._getFormatConfig(inst)));var controls=(!inst.inline?'":"");var buttonPanel=(showButtonPanel)?'
                          '+(isRTL?controls:"")+(this._isInRange(inst,gotoDate)?'":"")+(isRTL?"":controls)+"
                          ":"";var firstDay=parseInt(this._get(inst,"firstDay"),10);firstDay=(isNaN(firstDay)?0:firstDay);var dayNames=this._get(inst,"dayNames");var dayNamesShort=this._get(inst,"dayNamesShort");var dayNamesMin=this._get(inst,"dayNamesMin");var monthNames=this._get(inst,"monthNames");var monthNamesShort=this._get(inst,"monthNamesShort");var beforeShowDay=this._get(inst,"beforeShowDay");var showOtherMonths=this._get(inst,"showOtherMonths");var calculateWeek=this._get(inst,"calculateWeek")||this.iso8601Week;var endDate=inst.endDay?this._daylightSavingAdjust(new Date(inst.endYear,inst.endMonth,inst.endDay)):currentDate;var defaultDate=this._getDefaultDate(inst);var html="";for(var row=0;row'+(/all|left/.test(cornerClass)&&row==0?(isRTL?next:prev):"")+(/all|right/.test(cornerClass)&&row==0?(isRTL?prev:next):"")+this._generateMonthYearHeader(inst,drawMonth,drawYear,minDate,maxDate,selectedDate,row>0||col>0,monthNames,monthNamesShort)+'
                          ';var thead="";for(var dow=0;dow<7;dow++){var day=(dow+firstDay)%7;thead+="=5?' class="ui-datepicker-week-end"':"")+'>'+dayNamesMin[day]+""}calender+=thead+"";var daysInMonth=this._getDaysInMonth(drawYear,drawMonth);if(drawYear==inst.selectedYear&&drawMonth==inst.selectedMonth){inst.selectedDay=Math.min(inst.selectedDay,daysInMonth)}var leadDays=(this._getFirstDayOfMonth(drawYear,drawMonth)-firstDay+7)%7;var numRows=(isMultiMonth?6:Math.ceil((leadDays+daysInMonth)/7));var printDate=this._daylightSavingAdjust(new Date(drawYear,drawMonth,1-leadDays));for(var dRow=0;dRow";var tbody="";for(var dow=0;dow<7;dow++){var daySettings=(beforeShowDay?beforeShowDay.apply((inst.input?inst.input[0]:null),[printDate]):[true,""]);var otherMonth=(printDate.getMonth()!=drawMonth);var unselectable=otherMonth||!daySettings[0]||(minDate&&printDatemaxDate);tbody+='";printDate.setDate(printDate.getDate()+1);printDate=this._daylightSavingAdjust(printDate)}calender+=tbody+""}drawMonth++;if(drawMonth>11){drawMonth=0;drawYear++}calender+="
                          =currentDate.getTime()&&printDate.getTime()<=endDate.getTime()?" "+this._currentClass:"")+(printDate.getTime()==today.getTime()?" ui-datepicker-today":""))+'"'+((!otherMonth||showOtherMonths)&&daySettings[2]?' title="'+daySettings[2]+'"':"")+(unselectable?"":" onclick=\"DP_jQuery.datepicker._selectDay('#"+inst.id+"',"+drawMonth+","+drawYear+', this);return false;"')+">"+(otherMonth?(showOtherMonths?printDate.getDate():" "):(unselectable?''+printDate.getDate()+"":'=currentDate.getTime()&&printDate.getTime()<=endDate.getTime()?" ui-state-active":"")+'" href="#">'+printDate.getDate()+""))+"
                          "+(isMultiMonth?"
                        "+((numMonths[0]>0&&col==numMonths[1]-1)?'
                        ':""):"");group+=calender}html+=group}html+=buttonPanel+($.browser.msie&&parseInt($.browser.version,10)<7&&!inst.inline?'':"");inst._keyEvent=false;return html},_generateMonthYearHeader:function(inst,drawMonth,drawYear,minDate,maxDate,selectedDate,secondary,monthNames,monthNamesShort){minDate=(inst.rangeStart&&minDate&&selectedDate "}else{var inMinYear=(minDate&&minDate.getFullYear()==drawYear);var inMaxYear=(maxDate&&maxDate.getFullYear()==drawYear);monthHtml+='"}if(!showMonthAfterYear){html+=monthHtml+((secondary||changeMonth||changeYear)&&(!(changeMonth&&changeYear))?" ":"")}if(secondary||!changeYear){html+=''+drawYear+""}else{var years=this._get(inst,"yearRange").split(":");var year=0;var endYear=0;if(years.length!=2){year=drawYear-10;endYear=drawYear+10}else{if(years[0].charAt(0)=="+"||years[0].charAt(0)=="-"){year=drawYear+parseInt(years[0],10);endYear=drawYear+parseInt(years[1],10)}else{year=parseInt(years[0],10);endYear=parseInt(years[1],10)}}year=(minDate?Math.max(year,minDate.getFullYear()):year);endYear=(maxDate?Math.min(endYear,maxDate.getFullYear()):endYear);html+='"}if(showMonthAfterYear){html+=(secondary||changeMonth||changeYear?" ":"")+monthHtml}html+="
                      ";return html},_adjustInstDate:function(inst,offset,period){var year=inst.drawYear+(period=="Y"?offset:0);var month=inst.drawMonth+(period=="M"?offset:0);var day=Math.min(inst.selectedDay,this._getDaysInMonth(year,month))+(period=="D"?offset:0);var date=this._daylightSavingAdjust(new Date(year,month,day));var minDate=this._getMinMaxDate(inst,"min",true);var maxDate=this._getMinMaxDate(inst,"max");date=(minDate&&datemaxDate?maxDate:date);inst.selectedDay=date.getDate();inst.drawMonth=inst.selectedMonth=date.getMonth();inst.drawYear=inst.selectedYear=date.getFullYear();if(period=="M"||period=="Y"){this._notifyChange(inst)}},_notifyChange:function(inst){var onChange=this._get(inst,"onChangeMonthYear");if(onChange){onChange.apply((inst.input?inst.input[0]:null),[inst.selectedYear,inst.selectedMonth+1,inst])}},_getNumberOfMonths:function(inst){var numMonths=this._get(inst,"numberOfMonths");return(numMonths==null?[1,1]:(typeof numMonths=="number"?[1,numMonths]:numMonths))},_getMinMaxDate:function(inst,minMax,checkRange){var date=this._determineDate(this._get(inst,minMax+"Date"),null);return(!checkRange||!inst.rangeStart?date:(!date||inst.rangeStart>date?inst.rangeStart:date))},_getDaysInMonth:function(year,month){return 32-new Date(year,month,32).getDate()},_getFirstDayOfMonth:function(year,month){return new Date(year,month,1).getDay()},_canAdjustMonth:function(inst,offset,curYear,curMonth){var numMonths=this._getNumberOfMonths(inst);var date=this._daylightSavingAdjust(new Date(curYear,curMonth+(offset<0?offset:numMonths[1]),1));if(offset<0){date.setDate(this._getDaysInMonth(date.getFullYear(),date.getMonth()))}return this._isInRange(inst,date)},_isInRange:function(inst,date){var newMinDate=(!inst.rangeStart?null:this._daylightSavingAdjust(new Date(inst.selectedYear,inst.selectedMonth,inst.selectedDay)));newMinDate=(newMinDate&&inst.rangeStart=minDate)&&(!maxDate||date<=maxDate))},_getFormatConfig:function(inst){var shortYearCutoff=this._get(inst,"shortYearCutoff");shortYearCutoff=(typeof shortYearCutoff!="string"?shortYearCutoff:new Date().getFullYear()%100+parseInt(shortYearCutoff,10));return{shortYearCutoff:shortYearCutoff,dayNamesShort:this._get(inst,"dayNamesShort"),dayNames:this._get(inst,"dayNames"),monthNamesShort:this._get(inst,"monthNamesShort"),monthNames:this._get(inst,"monthNames")}},_formatDate:function(inst,day,month,year){if(!day){inst.currentDay=inst.selectedDay;inst.currentMonth=inst.selectedMonth;inst.currentYear=inst.selectedYear}var date=(day?(typeof day=="object"?day:this._daylightSavingAdjust(new Date(year,month,day))):this._daylightSavingAdjust(new Date(inst.currentYear,inst.currentMonth,inst.currentDay)));return this.formatDate(this._get(inst,"dateFormat"),date,this._getFormatConfig(inst))}});function extendRemove(target,props){$.extend(target,props);for(var name in props){if(props[name]==null||props[name]==undefined){target[name]=props[name]}}return target}function isArray(a){return(a&&(($.browser.safari&&typeof a=="object"&&a.length)||(a.constructor&&a.constructor.toString().match(/\Array\(\)/))))}$.fn.datepicker=function(options){if(!$.datepicker.initialized){$(document).mousedown($.datepicker._checkExternalClick).find("body").append($.datepicker.dpDiv);$.datepicker.initialized=true}var otherArgs=Array.prototype.slice.call(arguments,1);if(typeof options=="string"&&(options=="isDisabled"||options=="getDate")){return $.datepicker["_"+options+"Datepicker"].apply($.datepicker,[this[0]].concat(otherArgs))}if(options=="option"&&arguments.length==2&&typeof arguments[1]=="string"){return $.datepicker["_"+options+"Datepicker"].apply($.datepicker,[this[0]].concat(otherArgs))}return this.each(function(){typeof options=="string"?$.datepicker["_"+options+"Datepicker"].apply($.datepicker,[this].concat(otherArgs)):$.datepicker._attachDatepicker(this,options)})};$.datepicker=new Datepicker();$.datepicker.initialized=false;$.datepicker.uuid=new Date().getTime();$.datepicker.version="1.7.2";window.DP_jQuery=$})(jQuery);;/* * jQuery UI Progressbar 1.7.2 * * Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about) @@ -163,4 +139,511 @@ jQuery.effects||(function(d){d.effects={version:"1.7.2",save:function(g,h){for(v * Depends: * effects.core.js */ -(function(a){a.effects.transfer=function(b){return this.queue(function(){var f=a(this),h=a(b.options.to),e=h.offset(),g={top:e.top,left:e.left,height:h.innerHeight(),width:h.innerWidth()},d=f.offset(),c=a('
                      ').appendTo(document.body).addClass(b.options.className).css({top:d.top,left:d.left,height:f.innerHeight(),width:f.innerWidth(),position:"absolute"}).animate(g,b.duration,b.options.easing,function(){c.remove();(b.callback&&b.callback.apply(f[0],arguments));f.dequeue()})})}})(jQuery);; \ No newline at end of file +(function(a){a.effects.transfer=function(b){return this.queue(function(){var f=a(this),h=a(b.options.to),e=h.offset(),g={top:e.top,left:e.left,height:h.innerHeight(),width:h.innerWidth()},d=f.offset(),c=a('
                      ').appendTo(document.body).addClass(b.options.className).css({top:d.top,left:d.left,height:f.innerHeight(),width:f.innerWidth(),position:"absolute"}).animate(g,b.duration,b.options.easing,function(){c.remove();(b.callback&&b.callback.apply(f[0],arguments));f.dequeue()})})}})(jQuery);;/* + * jQuery UI Selectable @VERSION + * + * Copyright (c) 2009 AUTHORS.txt (http://ui.jquery.com/about) + * Dual licensed under the MIT (MIT-LICENSE.txt) + * and GPL (GPL-LICENSE.txt) licenses. + * + * http://docs.jquery.com/UI/Selectables + * + * Depends: + * ui.core.js + */ +(function($) { + + $.widget('ui.selectable', $.extend({}, $.ui.mouse, { + + _init: function() { + + var self = this; + this.items = $(this.options.filter, this.element); + this.element.addClass("ui-selectable"); + + //Set the currentFocus to the first item + this.currentFocus = this.items.eq(0); + + //Refresh item positions + this.refresh(); + + //Disable text selection + this.element.disableSelection(); + + //Prepare caret selection + if(this.options.lasso) this._mouseInit(); + + this.element + .bind('mousedown.selectable', function(event) { + + var item = self._targetIsItem(event.target); + if (!item) return; + + // If item is part of current selection and current + // selection is multiple, return and allow mouseup + // to fire (Windows gets this right too, OSX doesn't) + if(self._selection.length > 1 && $(item).hasClass(self.options.selectedClass)) { + return (self._listenForMouseUp = 1); + } + + if(self._trigger('beforeselect', event) === false) + return true; + + self._select(event, item); + self.element[0].focus(); + event.preventDefault(); + + }) + .bind('mouseup.selectable', function(event) { + if(self._listenForMouseUp) { + + self._listenForMouseUp = 0; + var item = self._targetIsItem(event.target); + if (!item) return; + + if(self._trigger('beforeselect', event) === false) + return true; + + self._select(event, item); + self.element[0].focus(); + event.preventDefault(); + } + }) + .bind('focus.selectable', function() { + self.currentFocus.addClass('ui-focused'); + }) + .bind('blur.selectable', function() { + self.currentFocus.removeClass('ui-focused'); + }) + .bind('keydown.selectable', function(event) { + + if(!self.options.keyboard) + return; + + if(self._trigger('beforeselect', event) === false) + return true; + + if(event.keyCode == $.ui.keyCode.DOWN) { + self.options.smart ? self.selectClosest('down', event) : self.selectNext(event); + event.preventDefault(); + } + + if(event.keyCode == $.ui.keyCode.RIGHT) { + self.options.smart ? self.selectClosest('right', event) : self.selectNext(event); + event.preventDefault(); + } + + if(event.keyCode == $.ui.keyCode.UP) { + self.options.smart ? self.selectClosest('up', event) : self.selectPrevious(event); + event.preventDefault(); + } + + if(event.keyCode == $.ui.keyCode.LEFT) { + self.options.smart ? self.selectClosest('left', event) : self.selectPrevious(event); + event.preventDefault(); + } + + if ((event.ctrlKey || event.metaKey) && event.keyCode == $.ui.keyCode.SPACE) { + self._toggleSelection(self.currentFocus, event); + } + + }); + + this.helper = $(document.createElement('div')) + .addClass("ui-selectable-lasso"); + + }, + + selectClosest: function(direction, event) { + + var current = [/(down|right)/.test(direction) ? 10000 : -10000, null], + overlap = 10000, + selfOffset = this.currentFocus.data('selectable-item'); + + $(this.options.filter, this.element).not(this.currentFocus).filter(':visible').each(function() { + + var $this = $(this), + offset = $this.data('selectable-item'), + distance = { + x: Math.abs(selfOffset.left - offset.left) + Math.abs((offset.left+this.offsetWidth) - (selfOffset.left+this.offsetWidth)), + y: Math.abs(selfOffset.top - offset.top) + Math.abs((offset.top+this.offsetHeight) - (selfOffset.top+this.offsetHeight)) + }; + + switch(direction) { + + case 'up': + if((selfOffset.top > offset.top && offset.top >= current[0]) && (offset.top != current[0] || distance.x < overlap)) { + current = [offset.top, $this]; + overlap = distance.x; + } + break; + + case 'down': + if((selfOffset.top < offset.top && offset.top <= current[0]) && (offset.top != current[0] || distance.x < overlap)) { + current = [offset.top, $this]; + overlap = distance.x; + } + break; + + case 'left': + if((selfOffset.left > offset.left && offset.left >= current[0]) && (offset.left != current[0] || distance.y < overlap)) { + current = [offset.left, $this]; + overlap = distance.y; + } + break; + + case 'right': + if((selfOffset.left < offset.left && offset.left <= current[0]) && (offset.left != current[0] || distance.y < overlap)) { + current = [offset.left, $this]; + overlap = distance.y; + } + break; + + } + + }); + + return current[1] ? this._select(event, current[1]) : false; + + }, + + destroy: function() { + this.element + .removeClass("ui-selectable ui-selectable-disabled") + .removeData("selectable") + .unbind(".selectable"); + this._mouseDestroy(); + }, + + _mouseCapture: function(event) { + //If the item we start dragging on is a selectable, we bail (if keyboard is used) + this.clickedOnItem = this._targetIsItem(event.target); + return !this.options.keyboard || !this.clickedOnItem; + }, + + _mouseStart: function(event) { + + var self = this, o = this.options; + this.opos = [event.pageX, event.pageY]; + + if (o.disabled) + return; + + //Cache positions + this.refresh(); + + //Trigger start event + this._trigger("start", event, this._uiHash()); + + // append and position helper (lasso) + $('body').append(this.helper); + this.helper.css({ + zIndex: 100, + position: "absolute", + left: event.clientX, + top: event.clientY, + width: 0, + height: 0 + }); + + //Tell the intersection that some start selected + this.items.filter('.'+this.options.selectedClass).each(function() { + if(event.metaKey) { + if(this != self.clickedOnItem) $.data(this, "selectable-item").startSelected = true; + } else self._removeFromSelection($(this), event); + }); + + }, + + _mouseDrag: function(event) { + + var self = this, o = this.options; + + if (o.disabled) + return; + + //Do the lasso magic + var x1 = this.opos[0], y1 = this.opos[1], x2 = event.pageX, y2 = event.pageY; + if (x1 > x2) { var tmp = x2; x2 = x1; x1 = tmp; } + if (y1 > y2) { var tmp = y2; y2 = y1; y1 = tmp; } + this.helper.css({left: x1, top: y1, width: x2-x1, height: y2-y1}); + + //Loop through all items and check overlaps + this.items.each(function() { + + var item = $.data(this, "selectable-item"); + + //prevent helper from being selected if appendTo: selectable + if (!item || item.element == self.element[0]) + return; + + var hit = false; + if (o.lasso && o.lasso.tolerance == 'touch') { + hit = ( !(item.left > x2 || item.right < x1 || item.top > y2 || item.bottom < y1) ); + } else if (o.lasso && o.lasso.tolerance == 'fit') { + hit = (item.left > x1 && item.right < x2 && item.top > y1 && item.bottom < y2); + } + + hit ? + item.startSelected ? self._removeFromSelection($(this), event) : self._addToSelection($(this), event) + : !item.startSelected ? self._removeFromSelection($(this), event) : self._addToSelection($(this), event); + + }); + + return false; + + }, + + _mouseStop: function(event) { + this._trigger("stop", event, this._uiHash()); + this.helper.remove(); + return false; + }, + + _targetIsItem: function(item) { + var found = $(item).parents().andSelf().filter(':data(selectable-item)'); + return found.length && found; + }, + + _selection: [], + + _clearSelection: function(triggerEvent) { + + var triggerItems = []; + + for (var i = this._selection.length - 1; i >= 0; i--){ + if(triggerEvent && this._selection[i].data('selectable-item').selected) triggerItems.push(this._selection[i]); + this._selection[i].removeClass(this.options.selectedClass); + this._selection[i].data('selectable-item').selected = false; + }; + + this._selection = []; + if(triggerEvent) this._trigger('unselect', triggerEvent, this._uiHash($($.map(triggerItems, function(i) { return i[0]; })), 'removed')); + + }, + + _toggleSelection: function(item, event) { + item.data('selectable-item').selected ? this._removeFromSelection(item, event) : this._addToSelection(item); + }, + + _addToSelection: function(item, triggerEvent) { + + if (item.data('selectable-item').selected) + return null; + + this._selection.push(item); + this.latestSelection = item; + item.addClass(this.options.selectedClass); + item.data('selectable-item').selected = true; + + if(triggerEvent) { + this._trigger('select', triggerEvent, $.extend({ lasso: true }, this._uiHash(item))); + } + + return item; + + }, + + _removeFromSelection: function(item, triggerEvent) { + + for (var i=0; i < this._selection.length; i++) { + if (this._selection[i][0] == item[0]) { + this._selection[i].removeClass(this.options.selectedClass); + this._selection[i].data('selectable-item').selected = false; + this._selection.splice(i,1); + if(triggerEvent) this._trigger('unselect', triggerEvent, this._uiHash($(item), 'removed')); + break; + } + }; + + }, + + _updateSelectionMouse: function(event) { + + var newlySelected = []; + + if (event.shiftKey && this.options.multiple) { + + //Clear the previous selection to make room for a shift selection + this._clearSelection(event); + + var index = this.items.index(this.latestWithoutModifier[0]) > this.items.index(this.currentFocus[0]) ? -1 : 1; + var i = this.latestWithoutModifier.data('selectable-item').selected ? this.items.eq(this.items.index(this.latestWithoutModifier[0])+index) : this.latestWithoutModifier; + while(i.length && i[0] != this.currentFocus[0]) { + i[0] == this.previousFocus[0] ? this._addToSelection(i) : newlySelected.push(this._addToSelection(i)); + i = this.items.eq(this.items.index(i[0])+index); + } + + //Readd the item with the current focus + newlySelected.push(this._addToSelection(this.currentFocus)); + + } else { + + if (event.metaKey) { + this._toggleSelection(this.currentFocus, event); + } else { + this._clearSelection(event); + newlySelected.push(this._addToSelection(this.currentFocus)); + this.latestWithoutModifier = this.currentFocus; + } + + } + + return $($.map(newlySelected, function(i) { return i[0]; })); + + }, + + _updateSelection: function(event, index) { + + var newlySelected = []; + + if (event.shiftKey && this.options.multiple) { + + if (this.currentFocus.data('selectable-item').selected) { + this._removeFromSelection(this.previousFocus, event); + } else { + + var index2 = this.items.index(this.latestSelection[0]) > this.items.index(this.currentFocus[0]) ? 1 : -1; + if (!this.previousFocus.data('selectable-item').selected) { + var i = index == index2 ? this.items.eq(this.items.index(this.previousFocus[0])+index2) : this.previousFocus; + while(i.length && !i.data('selectable-item').selected) { + newlySelected.push(this._addToSelection(i)); + i = this.items.eq(this.items.index(i[0])+index2); + } + } + + newlySelected.push(this._addToSelection(this.currentFocus)); + + } + + } else { + + //If the CTRL or Apple/Win key is pressed, only set focus + if (event.metaKey) + return; + + this._clearSelection(event); + newlySelected.push(this._addToSelection(this.currentFocus)); + this.latestWithoutModifier = this.currentFocus; + + } + + return $($.map(newlySelected, function(i) { return i[0]; })); + + }, + + _select: function(event, item) { + + //Set the current selection to the previous/next item + this.previousFocus = this.currentFocus; + this.currentFocus = $(item); + + this.previousFocus.removeClass('ui-focused'); + this.currentFocus.addClass('ui-focused'); + + //Set and update the selection + var newlySelected = this._updateSelectionMouse(event); + + //Trigger select event + if(newlySelected && newlySelected.length) this._trigger('select', event, this._uiHash(newlySelected, 'added')); + + }, + + _selectAdjacent: function(event, index) { + + var item = this.items.eq(this.items.index(this.currentFocus[0]) + index); + + //Bail if there's no previous/next item + if (!item.length) return; + + //Set the current selection to the previous/next item + this.previousFocus = this.currentFocus; + this.currentFocus = item; + + this.previousFocus.removeClass('ui-focused'); + this.currentFocus.addClass('ui-focused'); + + //Set and update the selection + var newlySelected = this._updateSelection(event, index); + + //Trigger select event + if(newlySelected && newlySelected.length) this._trigger('select', event, this._uiHash(newlySelected, 'added')); + + }, + + selectPrevious: function(event) { + this._selectAdjacent(event, -1); + }, + + selectNext: function(event) { + this._selectAdjacent(event, 1); + }, + + refresh: function() { + + var o = this.options; + this.items = $(o.filter, this.element); + this.items.each(function() { + var $this = $(this); + var pos = $this.offset(); + $.data(this, "selectable-item", { + left: pos.left, + top: pos.top, + right: pos.left + $this.width(), + bottom: pos.top + $this.height(), + startSelected: false, + selected: $this.hasClass(o.selectedClass) + }); + }); + + }, + + select: function(item) { + //TODO + }, + + deselect: function(item) { + if(!item) this._clearSelection(true); + //TODO: Deselect single elements + }, + + _uiHash: function(items, specialKey) { + var uiHash = { + previousFocus: this.previousFocus, + currentFocus: this.currentFocus, + selection: $($.map(this._selection, function(i) { return i[0]; })) + }; + if(specialKey) uiHash[specialKey] = items; + return uiHash; + } + + })); + + $.extend($.ui.selectable, { + defaults: { + + //TODO: Figure out how to move these defaults out + cancel: ":input,option", + delay: 0, + distance: 1, + appendTo: 'body', + + multiple: true, + smart: true, + filter: '> *', + + keyboard: true, + lasso: { + cancel: ":input,option", + delay: 0, + distance: 1, + tolerance: 'touch', + appendTo: 'body' + }, + + //Should we really delete that? + selectedClass: 'ui-state-selected' + } + }); + +})(jQuery); -- cgit v1.2.3 From 3823f65dfb4114caf9bd9cfbf730638927f6c970 Mon Sep 17 00:00:00 2001 From: Tim Almdal Date: Wed, 12 Aug 2009 21:55:25 -0700 Subject: Implement the first part of drag functionality. Having trouble getting visual feedback of the drop position between thumbnails, so this commit provides a checkpoint for trying various options --- modules/organize/controllers/organize.php | 9 +-- modules/organize/css/organize.css | 9 ++- modules/organize/helpers/organize_theme.php | 28 +++++++++ modules/organize/js/organize.js | 73 +++++++++++++++++++++- modules/organize/views/organize_dialog.html.php | 4 +- .../organize/views/organize_thumb_grid.html.php | 2 +- modules/organize/views/organize_tree.html.php | 4 +- 7 files changed, 116 insertions(+), 13 deletions(-) create mode 100644 modules/organize/helpers/organize_theme.php diff --git a/modules/organize/controllers/organize.php b/modules/organize/controllers/organize.php index 3a81ef4f..6f83f940 100644 --- a/modules/organize/controllers/organize.php +++ b/modules/organize/controllers/organize.php @@ -60,13 +60,14 @@ class Organize_Controller extends Controller { $v->album_icon = "gBranchEmpty"; $albums = $item->children(null, 0, array("type" => "album"), array("title" => "ASC")); - if ($albums->count()) { - $v->album_icon = empty($parents[$item->id]) ? "ui-icon-plus" : "ui-icon-minus"; - - foreach ($albums as $album) { + foreach ($albums as $album) { + if (access::can("view", $album)) { $v->children[] = $this->_tree($album, $parents); } } + if (count($v->children)) { + $v->album_icon = empty($parents[$item->id]) ? "ui-icon-plus" : "ui-icon-minus"; + } return $v; } } diff --git a/modules/organize/css/organize.css b/modules/organize/css/organize.css index a4b5fdbd..1cc7c92c 100644 --- a/modules/organize/css/organize.css +++ b/modules/organize/css/organize.css @@ -1,3 +1,4 @@ + /******************************************************************* * Dialog wide stylings */ @@ -92,7 +93,7 @@ } #gMicroThumbGrid { - padding: .5em; + padding: 1em; } .gMicroThumb { @@ -107,10 +108,14 @@ width: 9em; } -.gMicroThumb.ui-selected { +.gMicroThumb.ui-state-selected { opacity: 1; } +.ui-selectable-lasso { + z-index: 2000 !important; + border: 1px dashed #13A; +} .gThumbnail { padding: .5em; diff --git a/modules/organize/helpers/organize_theme.php b/modules/organize/helpers/organize_theme.php new file mode 100644 index 00000000..de812261 --- /dev/null +++ b/modules/organize/helpers/organize_theme.php @@ -0,0 +1,28 @@ +item(); + if ($item && access::can("edit", $item) && $item->is_album()) { + $theme->script("organize.js"); + $theme->css("organize.css"); + } + } +} diff --git a/modules/organize/js/organize.js b/modules/organize/js/organize.js index 05693200..c9408673 100644 --- a/modules/organize/js/organize.js +++ b/modules/organize/js/organize.js @@ -1,15 +1,83 @@ (function($) { $.organize = { + micro_thumb_draggable: { + distance: 10, + cursorAt: { left: -10, top: -10}, + appendTo: "#gOrganizeContentPane", + helper: function(event, ui) { + var selected = $("li.ui-state-selected img"), + set = $('
                      ').css({zIndex: 2000, width: 80, height: Math.ceil(selected.length / 5) * 16 }), + offset = $(this).offset(), + click = { left: event.pageX - offset.left, top: event.pageY - offset.top }; + + selected.each(function(i) { + var row = parseInt(i / 5); + var j = i - (row * 5); + + var o = $(this).offset(); + + var copy = $(this).clone() + .css({ + width: $(this).width(), height: $(this).height(), display: "block", + margin: 0, position: 'absolute', outline: '5px solid #fff', + left: o.left - event.pageX, top: o.top - event.pageY + }) + .appendTo(set) + .animate({width: 10, height: 10, outlineWidth: 1, margin: 1, left: (20 * j), top: (row * 20)}, 500); + }); + return set; + }, + start: function(event, ui) { + $("#gMicroThumbPanel").prepend("
                      "); + + $("#gMicroThumbPanel li.ui-state-selected").hide(); + }, + drag: function(event, ui) { + var container = $("#gMicroThumbPanel").get(0); + var scrollTop = container.scrollTop; + var height = $(container).height(); + if (event.pageY > height + scrollTop) { + container.scrollTop += height; + } else if (event.pageY < scrollTop) { + container.scrollTop -= height; + } + }, + stop: function(event, ui) { + $("li.ui-state-selected").show(); + } + }, + + droppable: { + accept: "*", + tolerance: "pointer", + greedy: true, + drop: function(event, ui) { + // @todo do a ajax call to send the rearrange request to the zerver + // organize/move/target_id/ + // post parameters + // before=id|after=id + // source=[id1, id2, ...] + // before or after not supplied then append to end + // return: json { + // result: success | msg, + // tree: null | new tree, + // content: new thumbgrid + // } + } + }, + /** * Dynamically initialize the organize dialog when it is displayed */ init: function(data) { + var self = this; // Deal with ui.jquery bug: http://dev.jqueryui.com/ticket/4475 (target 1.8?) $(".sf-menu li.sfHover ul").css("z-index", 68); $("#gDialog").dialog("option", "zIndex", 70); $("#gDialog").bind("dialogopen", function(event, ui) { $("#gOrganize").height($("#gDialog").innerHeight() - 20); $("#gMicroThumbPanel").height($("#gDialog").innerHeight() - 90); + $("#gOrganizeAlbumTree").height($("#gDialog").innerHeight() - 59); }); $("#gDialog").bind("dialogclose", function(event, ui) { @@ -23,7 +91,10 @@ $(".gBranchText span").click($.organize.collapse_or_expand_tree); $(".gBranchText").click($.organize.show_album); - $("#gMicroThumbGrid").selectable({filter: ".gMicroThumb"}); + $("#gMicroThumbPanel").selectable({filter: "li"}); + $("#gMicroThumbPanel img").draggable($.organize.micro_thumb_draggable); + $(".gOrganizeBranch").droppable($.organize.droppable); + $("#gMicroThumbPanel").droppable($.organize.droppable); }, /** diff --git a/modules/organize/views/organize_dialog.html.php b/modules/organize/views/organize_dialog.html.php index b946d82b..f8d6d792 100644 --- a/modules/organize/views/organize_dialog.html.php +++ b/modules/organize/views/organize_dialog.html.php @@ -1,5 +1,4 @@ -" />

                      p::purify($title))) ?>

                      @@ -11,7 +10,7 @@
                      -
                      +
                        @@ -39,7 +38,6 @@
                      - diff --git a/modules/organize/views/organize_thumb_grid.html.php b/modules/organize/views/organize_thumb_grid.html.php index 0d54c5c8..b6e3aa11 100644 --- a/modules/organize/views/organize_thumb_grid.html.php +++ b/modules/organize/views/organize_thumb_grid.html.php @@ -3,7 +3,7 @@
                    • " ref="id ?>"> - thumb_img(array("class" => "gThumbnail"), 90, true) ?> + thumb_img(array("class" => "gThumbnail", "ref" => $child->id), 90, true) ?>
                    • diff --git a/modules/organize/views/organize_tree.html.php b/modules/organize/views/organize_tree.html.php index 99b0dc1a..d2ef287a 100644 --- a/modules/organize/views/organize_tree.html.php +++ b/modules/organize/views/organize_tree.html.php @@ -1,11 +1,11 @@
                    • gBranchText"> + class=""> - title) ?> + title) ?>
                        "> -- cgit v1.2.3 From 5a84df9ac501b57cb5b472dc57590eef5e165dc3 Mon Sep 17 00:00:00 2001 From: Tim Almdal Date: Thu, 13 Aug 2009 10:56:50 -0700 Subject: Vertical scrolling of the thumb grid seems to work better now. Wasn't able to get the draggable autoscrolling working, so this is a poor replacemment. --- modules/organize/js/organize.js | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/modules/organize/js/organize.js b/modules/organize/js/organize.js index c9408673..aadc713a 100644 --- a/modules/organize/js/organize.js +++ b/modules/organize/js/organize.js @@ -3,7 +3,7 @@ micro_thumb_draggable: { distance: 10, cursorAt: { left: -10, top: -10}, - appendTo: "#gOrganizeContentPane", + //appendTo: "#gOrganizeContentPane", helper: function(event, ui) { var selected = $("li.ui-state-selected img"), set = $('
                        ').css({zIndex: 2000, width: 80, height: Math.ceil(selected.length / 5) * 16 }), @@ -28,21 +28,19 @@ return set; }, start: function(event, ui) { - $("#gMicroThumbPanel").prepend("
                        "); - $("#gMicroThumbPanel li.ui-state-selected").hide(); }, drag: function(event, ui) { - var container = $("#gMicroThumbPanel").get(0); - var scrollTop = container.scrollTop; - var height = $(container).height(); - if (event.pageY > height + scrollTop) { - container.scrollTop += height; - } else if (event.pageY < scrollTop) { - container.scrollTop -= height; + var top = $("#gMicroThumbPanel").offset().top; + var height = $("#gMicroThumbPanel").height(); + if (ui.offset.top > height + top - 20) { + $("#gMicroThumbPanel").get(0).scrollTop += 100; + } else if (ui.offset.top < top + 20) { + $("#gMicroThumbPanel").get(0).scrollTop = Math.max(0, $("#gMicroThumbPanel").get(0).scrollTop - 100); } }, stop: function(event, ui) { + // @todo delete this method when drop is implemented $("li.ui-state-selected").show(); } }, @@ -63,6 +61,7 @@ // tree: null | new tree, // content: new thumbgrid // } + // do forget to reset all the stuff in init when updating the content } }, @@ -92,7 +91,7 @@ $(".gBranchText").click($.organize.show_album); $("#gMicroThumbPanel").selectable({filter: "li"}); - $("#gMicroThumbPanel img").draggable($.organize.micro_thumb_draggable); + $("#gMicroThumbPanel li").draggable($.organize.micro_thumb_draggable); $(".gOrganizeBranch").droppable($.organize.droppable); $("#gMicroThumbPanel").droppable($.organize.droppable); }, -- cgit v1.2.3 From d758266fabff6c9fe4de22fce57bf00962150ee2 Mon Sep 17 00:00:00 2001 From: Tim Almdal Date: Thu, 13 Aug 2009 18:58:40 -0700 Subject: Add a visual indicator of the insertion point --- modules/organize/css/organize.css | 16 ++++++---- modules/organize/js/organize.js | 34 ++++++++++++++++------ .../organize/views/organize_thumb_grid.html.php | 5 +++- 3 files changed, 39 insertions(+), 16 deletions(-) diff --git a/modules/organize/css/organize.css b/modules/organize/css/organize.css index 1cc7c92c..d717bcae 100644 --- a/modules/organize/css/organize.css +++ b/modules/organize/css/organize.css @@ -96,19 +96,23 @@ padding: 1em; } +.gMicroThumbGridCell { + float: left; + font-size: 0.8em; + padding: .5em !important; + opacity: .5; + border-left: 1px hidden #13A; + border-right: 1px hidden #13A; +} + .gMicroThumb { display: block; - float: left; - font-size: .8em; height: 9em; - margin-bottom: 1em; - margin-left: 1em; - opacity: .5; text-align: center; width: 9em; } -.gMicroThumb.ui-state-selected { +.gMicroThumbGridCell.ui-state-selected { opacity: 1; } diff --git a/modules/organize/js/organize.js b/modules/organize/js/organize.js index aadc713a..a1b59676 100644 --- a/modules/organize/js/organize.js +++ b/modules/organize/js/organize.js @@ -3,10 +3,10 @@ micro_thumb_draggable: { distance: 10, cursorAt: { left: -10, top: -10}, - //appendTo: "#gOrganizeContentPane", + appendTo: "#gMicroThumbPanel", helper: function(event, ui) { - var selected = $("li.ui-state-selected img"), - set = $('
                        ').css({zIndex: 2000, width: 80, height: Math.ceil(selected.length / 5) * 16 }), + var selected = $(".ui-draggable.ui-state-selected img"), + set = $('
                        ').css({zIndex: 2000, width: 80, height: Math.ceil(selected.length / 5) * 16 }), offset = $(this).offset(), click = { left: event.pageX - offset.left, top: event.pageY - offset.top }; @@ -28,7 +28,7 @@ return set; }, start: function(event, ui) { - $("#gMicroThumbPanel li.ui-state-selected").hide(); + $("#gMicroThumbPanel .ui-state-selected").hide(); }, drag: function(event, ui) { var top = $("#gMicroThumbPanel").offset().top; @@ -39,9 +39,10 @@ $("#gMicroThumbPanel").get(0).scrollTop = Math.max(0, $("#gMicroThumbPanel").get(0).scrollTop - 100); } }, + // @todo delete this method when drop is implemented stop: function(event, ui) { - // @todo delete this method when drop is implemented - $("li.ui-state-selected").show(); + $(".ui-state-selected").show(); + $(".gMicroThumbGridCell").css("borderStyle", "none"); } }, @@ -50,7 +51,7 @@ tolerance: "pointer", greedy: true, drop: function(event, ui) { - // @todo do a ajax call to send the rearrange request to the zerver + // @todo do a ajax call to send the rearrange request to the server // organize/move/target_id/ // post parameters // before=id|after=id @@ -90,10 +91,24 @@ $(".gBranchText span").click($.organize.collapse_or_expand_tree); $(".gBranchText").click($.organize.show_album); - $("#gMicroThumbPanel").selectable({filter: "li"}); - $("#gMicroThumbPanel li").draggable($.organize.micro_thumb_draggable); + $("#gMicroThumbPanel").selectable({filter: ".gMicroThumbGridCell"}); $(".gOrganizeBranch").droppable($.organize.droppable); $("#gMicroThumbPanel").droppable($.organize.droppable); + + $.organize.set_handlers(); + }, + + set_handlers: function() { + $(".gMicroThumbGridCell").draggable($.organize.micro_thumb_draggable); + $(".gMicroThumbGridCell").mousemove(function(event) { + if ($(".gDragHelper").length) { + $(".gMicroThumbGridCell").css("borderStyle", "none"); + console.log("pageX:" + event.pageX + ", offset.left:" + $(this).offset().left + ", width:" + $(this).width()); + var side = event.pageX < $(this).offset().left + $(this).width() / 2 ? + "hidden hidden hidden solid" : "hidden solid hidden hidden"; + $(this).css("borderStyle", side); + } + }); }, /** @@ -119,6 +134,7 @@ var url = $("#gMicroThumbPanel").attr("ref").replace("__ITEM_ID__", id).replace("__OFFSET__", 0); $.get(url, function(data) { $("#gMicroThumbGrid").html(data); + $.organize.set_handlers(); }); } }; diff --git a/modules/organize/views/organize_thumb_grid.html.php b/modules/organize/views/organize_thumb_grid.html.php index b6e3aa11..b41c54e8 100644 --- a/modules/organize/views/organize_thumb_grid.html.php +++ b/modules/organize/views/organize_thumb_grid.html.php @@ -1,9 +1,11 @@ children(25, $offset) as $child): ?> -
                      • +
                        " ref="id ?>"> thumb_img(array("class" => "gThumbnail", "ref" => $child->id), 90, true) ?> +
                      • @@ -13,6 +15,7 @@ $.get("id/" . ($offset + 25)) ?>", function(data) { $("#gMicroThumbGrid").append(data); + $.organize.set_handlers(); } ); }, 50); -- cgit v1.2.3 From eeae2dc56c822a2fa32278bfe0f52bc43f665ec2 Mon Sep 17 00:00:00 2001 From: Tim Almdal Date: Thu, 13 Aug 2009 21:31:20 -0700 Subject: Added javascript portion of the drop functionality. At this point you can drag selected images and drop them on the micro thumb grid in a different position or onto a branch in the gallery tree. No ajax call is made, it just writes the generated url and post data to the console, so it only works in ff right now. --- modules/organize/js/organize.js | 90 +++++++++++++++------- modules/organize/views/organize_dialog.html.php | 3 + .../organize/views/organize_thumb_grid.html.php | 5 +- 3 files changed, 68 insertions(+), 30 deletions(-) diff --git a/modules/organize/js/organize.js b/modules/organize/js/organize.js index a1b59676..07c07286 100644 --- a/modules/organize/js/organize.js +++ b/modules/organize/js/organize.js @@ -46,23 +46,68 @@ } }, - droppable: { + content_droppable: { accept: "*", tolerance: "pointer", greedy: true, drop: function(event, ui) { - // @todo do a ajax call to send the rearrange request to the server - // organize/move/target_id/ - // post parameters - // before=id|after=id - // source=[id1, id2, ...] - // before or after not supplied then append to end - // return: json { - // result: success | msg, - // tree: null | new tree, - // content: new thumbgrid - // } - // do forget to reset all the stuff in init when updating the content + $.organize.do_drop({ + parent_id: $(".gBranchSelected").attr("ref"), + target_id: $(".currentDropTarget").attr("ref"), + position: $(".currentDropTarget").css("borderLeftStyle") == "solid" ? "before" : "after", + source: $(ui.helper).children("img") + }); + } + }, + + branch_droppable: { + accept: "*", + tolerance: "pointer", + greedy: true, + drop: function(event, ui) { + $.organize.do_drop({ + parent_id: $(event.target).attr("ref"), + target_id: -1, + position: "after", + source: $(ui.helper).children("img") + }); + } + }, + + do_drop:function(drop_parms) { + var source_ids = ""; + $(drop_parms.source).each(function(i) { + source_ids += (source_ids.length ? "&" : "") + "source_id[" + i + "]=" + $(this).attr("ref"); + }); + var url = drop_url.replace("__PARENT_ID__", drop_parms.parent_id) + .replace("__POSITION__", drop_parms.position) + .replace("__TARGET_ID__", drop_parms.target_id); + + console.group("do_drop"); + console.log("Generated url: " + url); + console.log("Post data(ids to move): " + source_ids); + console.groupEnd(); + // @todo do a ajax call to send the rearrange request to the server + // organize/move/parent_id/before|after/-1|target_id + // post parameters + // source=[id1, id2, ...] + // before or after not supplied then append to end + // return: json { + // result: success | msg, + // tree: null | new tree, + // content: new thumbgrid + // } + // do forget to reset all the stuff in init when updating the content + }, + + mouse_move_handler: function(event) { + if ($(".gDragHelper").length) { + $(".gMicroThumbGridCell").css("borderStyle", "hidden"); + $(".currentDropTarget").removeClass("currentDropTarget"); + var borderStyle = event.pageX < $(this).offset().left + $(this).width() / 2 ? + "borderLeftStyle" : "borderRightStyle"; + $(this).css(borderStyle, "solid"); + $(this).addClass("currentDropTarget"); } }, @@ -88,27 +133,18 @@ $("#gDialog").dialog("close"); }); - $(".gBranchText span").click($.organize.collapse_or_expand_tree); - $(".gBranchText").click($.organize.show_album); - $("#gMicroThumbPanel").selectable({filter: ".gMicroThumbGridCell"}); - $(".gOrganizeBranch").droppable($.organize.droppable); - $("#gMicroThumbPanel").droppable($.organize.droppable); + $("#gMicroThumbPanel").droppable($.organize.content_droppable); $.organize.set_handlers(); }, set_handlers: function() { $(".gMicroThumbGridCell").draggable($.organize.micro_thumb_draggable); - $(".gMicroThumbGridCell").mousemove(function(event) { - if ($(".gDragHelper").length) { - $(".gMicroThumbGridCell").css("borderStyle", "none"); - console.log("pageX:" + event.pageX + ", offset.left:" + $(this).offset().left + ", width:" + $(this).width()); - var side = event.pageX < $(this).offset().left + $(this).width() / 2 ? - "hidden hidden hidden solid" : "hidden solid hidden hidden"; - $(this).css("borderStyle", side); - } - }); + $(".gMicroThumbGridCell").mousemove($.organize.mouse_move_handler); + $(".gOrganizeBranch").droppable($.organize.branch_droppable); + $(".gBranchText span").click($.organize.collapse_or_expand_tree); + $(".gBranchText").click($.organize.show_album); }, /** diff --git a/modules/organize/views/organize_dialog.html.php b/modules/organize/views/organize_dialog.html.php index f8d6d792..982eba9e 100644 --- a/modules/organize/views/organize_dialog.html.php +++ b/modules/organize/views/organize_dialog.html.php @@ -1,4 +1,7 @@ +

                        p::purify($title))) ?>

                        diff --git a/modules/organize/views/organize_thumb_grid.html.php b/modules/organize/views/organize_thumb_grid.html.php index b41c54e8..671e0ce4 100644 --- a/modules/organize/views/organize_thumb_grid.html.php +++ b/modules/organize/views/organize_thumb_grid.html.php @@ -1,9 +1,8 @@ children(25, $offset) as $child): ?> -
                      • +
                      • " - ref="id ?>"> + class="gMicroThumb is_album() ? "gAlbum" : "gPhoto" ?>"> thumb_img(array("class" => "gThumbnail", "ref" => $child->id), 90, true) ?>
                      • -- cgit v1.2.3 From 76f320ab3d6b1f67055dd913eb5811d0d113682a Mon Sep 17 00:00:00 2001 From: Tim Almdal Date: Sun, 16 Aug 2009 12:36:14 -0700 Subject: In this patch, drag now works to the album tree, but the progress bar is not showing. As well fixed a problem where selectable single clink no longer worked when the album was reloaded. --- modules/gallery/controllers/combined.php | 9 +- modules/organize/controllers/organize.php | 121 +++++++++++++++++++-- modules/organize/js/organize.js | 138 ++++++++++++++---------- modules/organize/views/organize_dialog.html.php | 7 +- 4 files changed, 208 insertions(+), 67 deletions(-) diff --git a/modules/gallery/controllers/combined.php b/modules/gallery/controllers/combined.php index 9a790fdf..c1f42bfe 100644 --- a/modules/gallery/controllers/combined.php +++ b/modules/gallery/controllers/combined.php @@ -42,22 +42,23 @@ class Combined_Controller extends Controller { private function _emit($type, $key) { $input = Input::instance(); + // We don't need to save the session for this request + Session::abort_save(); + // Our data is immutable, so if they already have a copy then it needs no updating. if ($input->server("HTTP_IF_MODIFIED_SINCE")) { header('HTTP/1.0 304 Not Modified'); header("Expires: Tue, 19 Jan 2038 00:00:00 GMT"); header("Cache-Control: max-age=2678400"); header('Pragma: public'); - return; + Kohana::close_buffers(false); + return ""; } if (empty($key)) { Kohana::show_404(); } - // We don't need to save the session for this request - Session::abort_save(); - $cache = Cache::instance(); $use_gzip = function_exists("gzencode") && stripos($input->server("HTTP_ACCEPT_ENCODING"), "gzip") !== false && diff --git a/modules/organize/controllers/organize.php b/modules/organize/controllers/organize.php index 6f83f940..1c4a3a69 100644 --- a/modules/organize/controllers/organize.php +++ b/modules/organize/controllers/organize.php @@ -32,8 +32,8 @@ class Organize_Controller extends Controller { } $parents[$item->id] = 1; - $v->album_tree = $this->_tree($root, $parents); - $v->micro_thumb_grid = $this->_get_micro_thumb_grid($item, 0); + $v->album_tree = self::_tree($root, $parents); + $v->micro_thumb_grid = self::_get_micro_thumb_grid($item, 0); print $v; } @@ -41,17 +41,77 @@ class Organize_Controller extends Controller { $item = ORM::factory("item", $item_id); access::required("view", $item); access::required("edit", $item); - print $this->_get_micro_thumb_grid($item, $offset); + print self::_get_micro_thumb_grid($item, $offset); } - private function _get_micro_thumb_grid($item, $offset) { + function move($target_id) { + access::verify_csrf(); + + $task_def = Task_Definition::factory() + ->callback("Organize_Controller::move_task_handler") + ->description(t("Move images")) + ->name(t("Move Images")); + $task = task::create($task_def, array("target_id" => $target_id, + "source_ids" => $this->input->post("source_ids"))); + + print json_encode( + array("result" => "started", + "status" => $task->status, + "url" => url::site("organize/run/$task->id?csrf=" . access::csrf_token()))); + } + + function rearrange($target_id, $before) { + access::verify_csrf(); + $target = ORM::factory("item", $target_id); + $parent = $target->parent(); + access::required("view", $parent); + access::required("edit", $parent); + + $task_def = Task_Definition::factory() + ->callback("Organize_Controller::rearrange_task_handler") + ->description(t("Rearrange Image")) + ->name(t("Rearrange Images")); + $task = task::create($task_def, array("target_id" => $target_id, "before" => $before, + "current" => 0, + "source_ids" => $this->input->post("source_ids"))); + + print json_encode( + array("result" => "started", + "status" => $task->status, + "url" => url::site("organize/run/$task->id?csrf=" . access::csrf_token()))); + } + + private static function _get_micro_thumb_grid($item, $offset) { $v = new View("organize_thumb_grid.html"); $v->item = $item; $v->offset = $offset; return $v; } - private function _tree($item, $parents) { + /** + * Run the task + */ + function run($task_id) { + access::verify_csrf(); + + $task = ORM::factory("task", $task_id); + if (!$task->loaded || $task->owner_id != user::active()->id) { + access::forbidden(); + } + + $task = task::run($task_id); + $results = array("done" => $task->done, "status" => $task->status, + "percent_complete" => $task->percent_complete); + foreach (array("tree", "content") as $data) { + $value = $task->get($data, false); + if ($value !== false) { + $results[$data] = $value; + } + } + print json_encode($results); + } + + private static function _tree($item, $parents) { $v = new View("organize_tree.html"); $v->album = $item; $keys = array_keys($parents); @@ -62,7 +122,7 @@ class Organize_Controller extends Controller { $albums = $item->children(null, 0, array("type" => "album"), array("title" => "ASC")); foreach ($albums as $album) { if (access::can("view", $album)) { - $v->children[] = $this->_tree($album, $parents); + $v->children[] = self::_tree($album, $parents); } } if (count($v->children)) { @@ -70,4 +130,53 @@ class Organize_Controller extends Controller { } return $v; } + + static function move_task_handler($task) { + $start = microtime(true); + if ($task->percent_complete == 0) { + batch::start(); + } + + $target = ORM::factory("item", $task->get("target_id")); + $source_ids = $task->get("source_ids", array()); + $idx = $task->get("current", 0); + $count = 0; + for (; $idx < count($source_ids) && microtime(true) - $start < 0.5; $idx++) { + item::move(ORM::factory("item", $source_ids[$idx]), $target); + $count++; + } + $task->set("current", $idx); + $task->percent_complete = ceil($idx / count($source_ids) * 100); + $task->status = t2("Moved one file", "Moved %count files", $count); + if ($task->percent_complete == 100) { + batch::stop(); + $task->done = true; + $task->state = "success"; + $parents = array(); + foreach ($target->parents() as $parent) { + $parents[$parent->id] = 1; + } + $parents[$target->id] = 1; + // @TODO do we want to set a flag and then generate them in the run method so we don't + // potentially store large data items in the task? + $task->set("tree", self::_tree(ORM::factory("item", 1), $parents)->__toString()); + $task->set("content", self::_get_micro_thumb_grid($target, 0)->__toString()); + } + } + + static function rearrange_task_handler($task) { + // @todo need to + // 1) reset the weights based on the current sort order + // 2) when they are all copied, change the sort order of the parent to "weight" + $task->percent_complete = 100; + //$start = microtime(true); + //$mode = $task->get("mode", "init"); + //$start = microtime(true); + // if (microtime(true) - $start > 0.5) { + // break; + $task->done = true; + $task->state = "success"; + $target = ORM::factory("item", $task->get("target_id")); + $task->set("content", self::_get_micro_thumb_grid($target, 0)->__toString()); + } } diff --git a/modules/organize/js/organize.js b/modules/organize/js/organize.js index 07c07286..2d7c99fc 100644 --- a/modules/organize/js/organize.js +++ b/modules/organize/js/organize.js @@ -1,32 +1,37 @@ (function($) { $.organize = { micro_thumb_draggable: { + handle: ".ui-state-selected", distance: 10, cursorAt: { left: -10, top: -10}, appendTo: "#gMicroThumbPanel", helper: function(event, ui) { - var selected = $(".ui-draggable.ui-state-selected img"), - set = $('
                        ').css({zIndex: 2000, width: 80, height: Math.ceil(selected.length / 5) * 16 }), - offset = $(this).offset(), - click = { left: event.pageX - offset.left, top: event.pageY - offset.top }; - - selected.each(function(i) { - var row = parseInt(i / 5); - var j = i - (row * 5); - - var o = $(this).offset(); - - var copy = $(this).clone() - .css({ - width: $(this).width(), height: $(this).height(), display: "block", - margin: 0, position: 'absolute', outline: '5px solid #fff', - left: o.left - event.pageX, top: o.top - event.pageY - }) - .appendTo(set) - .animate({width: 10, height: 10, outlineWidth: 1, margin: 1, left: (20 * j), top: (row * 20)}, 500); - }); - return set; + var selected = $(".ui-draggable.ui-state-selected img"); + if (selected.length) { + var set = $('
                        ').css({zIndex: 2000, width: 80, height: Math.ceil(selected.length / 5) * 16 }), + offset = $(this).offset(), + click = { left: event.pageX - offset.left, top: event.pageY - offset.top }; + + selected.each(function(i) { + var row = parseInt(i / 5); + var j = i - (row * 5); + + var o = $(this).offset(); + + var copy = $(this).clone() + .css({ + width: $(this).width(), height: $(this).height(), display: "block", + margin: 0, position: 'absolute', outline: '5px solid #fff', + left: o.left - event.pageX, top: o.top - event.pageY + }) + .appendTo(set) + .animate({width: 10, height: 10, outlineWidth: 1, margin: 1, left: (20 * j), top: (row * 20)}, 500); + }); + return set; + } + return null; }, + start: function(event, ui) { $("#gMicroThumbPanel .ui-state-selected").hide(); }, @@ -52,9 +57,8 @@ greedy: true, drop: function(event, ui) { $.organize.do_drop({ - parent_id: $(".gBranchSelected").attr("ref"), - target_id: $(".currentDropTarget").attr("ref"), - position: $(".currentDropTarget").css("borderLeftStyle") == "solid" ? "before" : "after", + url: rearrange_url.replace("__TARGET_ID__", $(".currentDropTarget").attr("ref")) + .replace("__BEFORE__", $(".currentDropTarget").css("borderLeftStyle") == "solid"), source: $(ui.helper).children("img") }); } @@ -66,40 +70,61 @@ greedy: true, drop: function(event, ui) { $.organize.do_drop({ - parent_id: $(event.target).attr("ref"), - target_id: -1, - position: "after", + url: move_url.replace("__TARGET_ID__", $(event.target).attr("ref")), source: $(ui.helper).children("img") }); } }, - do_drop:function(drop_parms) { - var source_ids = ""; - $(drop_parms.source).each(function(i) { - source_ids += (source_ids.length ? "&" : "") + "source_id[" + i + "]=" + $(this).attr("ref"); + do_drop:function(options) { + var source_ids = []; + $(options.source).each(function(i) { + source_ids.push($(this).attr("ref")); }); - var url = drop_url.replace("__PARENT_ID__", drop_parms.parent_id) - .replace("__POSITION__", drop_parms.position) - .replace("__TARGET_ID__", drop_parms.target_id); - - console.group("do_drop"); - console.log("Generated url: " + url); - console.log("Post data(ids to move): " + source_ids); - console.groupEnd(); - // @todo do a ajax call to send the rearrange request to the server - // organize/move/parent_id/before|after/-1|target_id - // post parameters - // source=[id1, id2, ...] - // before or after not supplied then append to end - // return: json { - // result: success | msg, - // tree: null | new tree, - // content: new thumbgrid - // } - // do forget to reset all the stuff in init when updating the content + + if (source_ids.length) { + $("#gOrganize .gProgressBar").progressbar().progressbar("value", 0); + $("#gOrganizeProgress").slideDown("fast", function() { + $.ajax({ + url: options.url, + type: "POST", + async: false, + data: { "source_ids[]": source_ids }, + dataType: "json", + success: function(data, textStatus) { + $("#gStatus").html(data.status); + $("#gOrganize .gProgressBar").progressbar("value", data.percent_complete); + setTimeout(function() { $.organize._run_task(data.url); }, 0); + } + }); + }); + } }, + _run_task: function(url) { + $.ajax({ + url: url, + async: false, + dataType: "json", + success: function(data, textStatus) { + $("#gStatus").html(data.status); + $("#gOrganize .gProgressBar").progressbar("value", data.percent_complete); + if (data.done) { + $("#gProgress").slideUp(); + // Don't forget to refresh the content pane and tree + if (data.tree) { + $("#gOrganizeAlbumTree").html(data.tree); + } + if (data.content) { + $("#gMicroThumbGrid").html(data.content); + } + $.organize.set_handlers(); + } else { + setTimeout(function() { $.organize._run_task(url); }, 0); + } + } + }); + }, mouse_move_handler: function(event) { if ($(".gDragHelper").length) { $(".gMicroThumbGridCell").css("borderStyle", "hidden"); @@ -121,8 +146,8 @@ $("#gDialog").dialog("option", "zIndex", 70); $("#gDialog").bind("dialogopen", function(event, ui) { $("#gOrganize").height($("#gDialog").innerHeight() - 20); - $("#gMicroThumbPanel").height($("#gDialog").innerHeight() - 90); - $("#gOrganizeAlbumTree").height($("#gDialog").innerHeight() - 59); + $("#gMicroThumbPanel").height($("#gDialog").innerHeight() - 120); + $("#gOrganizeAlbumTree").height($("#gDialog").innerHeight() - 89); }); $("#gDialog").bind("dialogclose", function(event, ui) { @@ -133,18 +158,18 @@ $("#gDialog").dialog("close"); }); - $("#gMicroThumbPanel").selectable({filter: ".gMicroThumbGridCell"}); - $("#gMicroThumbPanel").droppable($.organize.content_droppable); - $.organize.set_handlers(); }, set_handlers: function() { + $("#gMicroThumbPanel").selectable({filter: ".gMicroThumbGridCell"}); + $("#gMicroThumbPanel").droppable($.organize.content_droppable); + $(".gMicroThumbGridCell").draggable($.organize.micro_thumb_draggable); $(".gMicroThumbGridCell").mousemove($.organize.mouse_move_handler); $(".gOrganizeBranch").droppable($.organize.branch_droppable); - $(".gBranchText span").click($.organize.collapse_or_expand_tree); $(".gBranchText").click($.organize.show_album); + $(".gOrganizeBranch .ui-icon").click($.organize.collapse_or_expand_tree); }, /** @@ -164,6 +189,7 @@ if ($(event.currentTarget).hasClass("gBranchSelected")) { return; } + $("#gMicroThumbPanel").selectable("destroy"); var id = $(event.currentTarget).attr("ref"); $(".gBranchSelected").removeClass("gBranchSelected"); $("#gOrganizeBranch-" + id).addClass("gBranchSelected"); diff --git a/modules/organize/views/organize_dialog.html.php b/modules/organize/views/organize_dialog.html.php index 982eba9e..46f9ad9b 100644 --- a/modules/organize/views/organize_dialog.html.php +++ b/modules/organize/views/organize_dialog.html.php @@ -1,6 +1,7 @@

                        p::purify($title))) ?>

                        @@ -39,6 +40,10 @@
                        +
                    • "; + $theme->script("slideshow.js"); + $theme->css("slideshow.css"); } } diff --git a/modules/slideshow/js/slideshow.js b/modules/slideshow/js/slideshow.js new file mode 100644 index 00000000..0f04a206 --- /dev/null +++ b/modules/slideshow/js/slideshow.js @@ -0,0 +1,149 @@ +(function($) { + $.gallery_slideshow = { + interval: 4000, + timer: null, + init: function(data) { + var self = this; + var size = $.gallery_get_viewport_size(); + $("body").append( + '
                      ' + + '' + + '
                      '); + $().bind("mousemove", $.gallery_slideshow._mouse_over); + + // array of {url: xxx, width: nnn, height: nnn} + for (var i=0; i < data.length; i++) { + var position = $.gallery_slideshow._autofit_image(data[i].width, data[i].height); + $("#gSlideShowImages").append( + ''); + if (i == 0) { + $("#gSlideShowImages #img_0").load(function() { + $.gallery_slideshow._show_image(null); + setTimeout(function() {$("#gSlideshowButtonPanel").hide();}, + $.gallery_slideshow.interval); + }); + } + } + }, + + close: function(event) { + $("#gSlideShowImages img.gSlideShowing").toggle(); + $.gallery_slideshow.pause(); + $("#gSlideshowOverlay").remove(); + $("#gSlideShowImages").remove(); + $("#gSlideshowButtonPanel").remove(); + $().unbind("mousemove", $.gallery_slideshow._mouse_over); + }, + + previous: function() { + $.gallery_slideshow.pause(); + var next_image = $("#gSlideShowImages img.gSlideShowing").prev(); + if (next_image.length == 0) { + next_image = $("#gSlideShowImages img:last"); + } + $.gallery_slideshow._show_image(next_image); + }, + + next: function() { + $.gallery_slideshow.pause(); + var next_image = $("#gSlideShowImages img.gSlideShowing").next(); + if (next_image.length == 0) { + next_image = $("#gSlideShowImages img:first"); + } + $.gallery_slideshow._show_image(next_image); + }, + + pause: function() { + if ($.gallery_slideshow.timer) { + $("#gSlideshowPause").toggle(); + $("#gSlideshowResume").toggle(); + clearTimeout($.gallery_slideshow.timer); + $.gallery_slideshow.timer = null; + } + }, + + resume: function() { + $("#gSlideshowPause").toggle(); + $("#gSlideshowResume").toggle(); + $.gallery_slideshow._show_image(null); + }, + + _mouse_over: function(event) { + var size = $.gallery_get_viewport_size(); + if (event.pageY < size.height() && size.height() - 100 <= event.pageY) { + $("#gSlideshowButtonPanel").show(); + } else { + $("#gSlideshowButtonPanel").hide(); + } + }, + + _autofit_image: function(imageWidth, imageHeight) { + var size = $.gallery_get_viewport_size(); + + var ratio = size.width() / imageWidth; + imageWidth *= ratio; + imageHeight *= ratio; + + /* after scaling the width, check that the height fits */ + if (imageHeight > size.height()) { + ratio = size.height() / imageHeight; + imageWidth *= ratio; + imageHeight *= ratio; + } + + // handle the case where the calculation is almost zero (2.14e-14) + return { + top: Number((size.height() - imageHeight) / 2), + left: Number((size.width() - imageWidth) / 2), + width: Number(imageWidth), + height: Number(imageHeight) + }; + }, + + // If next_image is not null, then this a call from prev or next + _show_image: function(next_image) { + var reset_timer = false; + if (next_image == null) { + next_image = $("#gSlideShowImages img.gSlideShowing").next(); + if (next_image.length == 0) { + next_image = $("#gSlideShowImages img:first"); + } + reset_timer = true; + } + next_image.addClass("gSlideShowNextImage"); + + var zIndex = parseInt(next_image.css("zIndex")); + next_image.css("zIndex", zIndex + 1); + next_image.fadeIn("slow", function() { + var current = $("#gSlideShowImages img.gSlideShowing"); + if (current.length) { + current.hide(); + current.removeClass("gSlideShowing"); + } + $(".gSlideShowNextImage").addClass("gSlideShowing").removeClass("gSlideShowNextImage") + .css("zIndex", zIndex); + if (reset_timer) { + $.gallery_slideshow.timer = + setTimeout(function() {$.gallery_slideshow._show_image(null);}, + $.gallery_slideshow.interval); + } + }); + } + }; +})(jQuery); + +$(document).ready(function() { + $("#gSlideshowLink").click(function(event) { + event.preventDefault(); + $.get($(event.currentTarget).attr("href"), {}, $.gallery_slideshow.init, "json"); + return false; + }); +}); diff --git a/modules/slideshow/module.info b/modules/slideshow/module.info index 6841199a..b56eac81 100644 --- a/modules/slideshow/module.info +++ b/modules/slideshow/module.info @@ -1,3 +1,3 @@ name = "Slideshow" description = "Allows users to view a slideshow of photos" -version = 1 +version = 2 -- cgit v1.2.3 From 152caf5195e3bbcdb353707fed5683ed07927f47 Mon Sep 17 00:00:00 2001 From: Tim Almdal Date: Thu, 20 Aug 2009 08:47:42 -0700 Subject: Resolve issues with show the wrong album when slideshow is invoked from a photo page. In addition, implement the slideshow based on tags. --- modules/slideshow/controllers/slideshow.php | 37 ++++++++++----------------- modules/slideshow/helpers/slideshow_event.php | 2 +- 2 files changed, 15 insertions(+), 24 deletions(-) diff --git a/modules/slideshow/controllers/slideshow.php b/modules/slideshow/controllers/slideshow.php index 6649b00b..8c4d1f46 100644 --- a/modules/slideshow/controllers/slideshow.php +++ b/modules/slideshow/controllers/slideshow.php @@ -22,32 +22,23 @@ class Slideshow_Controller extends Controller { $item = ORM::factory("item", $item_id); access::required("view", $item); - print $this->_build_image_list($item->children()); + print json_encode(array_values($this->_build_image_list($item->children()))); } function photo($item_id) { $item = ORM::factory("item", $item_id); access::required("view", $item); - print $this->_build_image_list($item->parent()->children()); - } - - function tag($item_id) { - $item = ORM::factory("item", $item_id); - $root = $item->id == 1 ? $item : ORM::factory("item", 1); - access::required("view", $item); + $images = $this->_build_image_list($item->parent()->children()); + $this_photo = array_search($item_id, array_keys($images)); + $images = array_merge(array_slice($images, $this_photo), array_slice($images, 0, $this_photo)); - $v = new View("organize_dialog.html"); - $v->title = $item->title; - $parents = array(); - foreach ($item->parents() as $parent) { - $parents[$parent->id] = 1; - } - $parents[$item->id] = 1; + print json_encode($images); + } - $v->album_tree = self::_tree($root, $parents); - $v->micro_thumb_grid = self::_get_micro_thumb_grid($item, 0); - print $v; + function tag($tag_id) { + $tag = ORM::factory("tag", $tag_id); + print json_encode(array_values($this->_build_image_list($tag->items()))); } private function _build_image_list($children) { @@ -57,17 +48,17 @@ class Slideshow_Controller extends Controller { case "album": if (!empty($child->album_cover_item_id)) { $cover = ORM::factory("item", $child->album_cover_item_id); - $resizes[] = array("url" => $cover->resize_url(), "width" => $cover->resize_width, - "height" => $cover->resize_height); + $resizes[$child->id] = array("url" => $cover->resize_url(), + "width" => $cover->resize_width, "height" => $cover->resize_height); } break; case "photo": - $resizes[] = array("url" => $child->resize_url(), "width" => $child->resize_width, - "height" => $child->resize_height); + $resizes[$child->id] = array("url" => $child->resize_url(), + "width" => $child->resize_width, "height" => $child->resize_height); break; } } - return json_encode($resizes); + return $resizes; } } diff --git a/modules/slideshow/helpers/slideshow_event.php b/modules/slideshow/helpers/slideshow_event.php index 7060fa1d..926b4da1 100644 --- a/modules/slideshow/helpers/slideshow_event.php +++ b/modules/slideshow/helpers/slideshow_event.php @@ -28,7 +28,7 @@ class slideshow_event_Core { } static function photo_menu($menu, $theme) { - $item = $theme->item()->parent(); + $item = $theme->item(); $menu->append(Menu::factory("link") ->id("slideshow") ->label(t("View slideshow")) -- cgit v1.2.3 From 74d79dc81929111edebfb47912f18521639241f0 Mon Sep 17 00:00:00 2001 From: Tim Almdal Date: Thu, 20 Aug 2009 12:53:20 -0700 Subject: Refactor the _auto_fit method in gallery.show_full_size to a common method in gallery.common.js --- lib/gallery.common.js | 25 +++++++++++++++++++++++++ lib/gallery.show_full_size.js | 39 +++++---------------------------------- 2 files changed, 30 insertions(+), 34 deletions(-) diff --git a/lib/gallery.common.js b/lib/gallery.common.js index 06775d79..844e219b 100644 --- a/lib/gallery.common.js +++ b/lib/gallery.common.js @@ -125,5 +125,30 @@ ); }; + $.gallery_auto_fit_window = function(imageWidth, imageHeight) { + var size = $.gallery_get_viewport_size(); + var width = size.width() - 6, + height = size.height() - 6; + + var ratio = width / imageWidth; + imageWidth *= ratio; + imageHeight *= ratio; + + /* after scaling the width, check that the height fits */ + if (imageHeight > height) { + ratio = height / imageHeight; + imageWidth *= ratio; + imageHeight *= ratio; + } + + // handle the case where the calculation is almost zero (2.14e-14) + return { + top: Number((height - imageHeight) / 2), + left: Number((width - imageWidth) / 2), + width: Number(imageWidth), + height: Number(imageHeight) + }; + }; + })(jQuery); diff --git a/lib/gallery.show_full_size.js b/lib/gallery.show_full_size.js index c32195f6..2f365f0d 100644 --- a/lib/gallery.show_full_size.js +++ b/lib/gallery.show_full_size.js @@ -3,48 +3,19 @@ * @todo Move inline CSS out to external style sheet (theme style sheet) */ $.gallery_show_full_size = function(image_url, image_width, image_height) { - /* - * Calculate the size of the image panel based on the size of the image and the size of the - * window. Scale the image so the entire panel fits in the view port. - */ - function _auto_fit(imageWidth, imageHeight) { - // ui-dialog gives a padding of 2 pixels - var windowWidth = $(window).width() - 10; - var windowHeight = $(window).height() - 10; - - /* If the width is greater then scale the image width first */ - if (imageWidth > windowWidth) { - var ratio = windowWidth / imageWidth; - imageWidth *= ratio; - imageHeight *= ratio; - } - /* after scaling the width, check that the height fits */ - if (imageHeight > windowHeight) { - var ratio = windowHeight / imageHeight; - imageWidth *= ratio; - imageHeight *= ratio; - } - - // handle the case where the calculation is almost zero (2.14e-14) - return { - top: Number((windowHeight - imageHeight) / 2), - left: Number((windowWidth - imageWidth) / 2), - width: Number(imageWidth), - height: Number(imageHeight) - }; - } - var width = $(document).width(); var height = $(document).height(); + var size = $.gallery_get_viewport_size(); $("body").append('
                      '); - var image_size = _auto_fit(image_width, image_height); + var image_size = $.gallery_auto_fit_window(image_width, image_height); $("body").append('
                      Date: Fri, 21 Aug 2009 03:53:20 +0800 Subject: Refactor the _auto_fit method in gallery.show_full_size to a common method in gallery.common.js Signed-off-by: Tim Almdal --- lib/gallery.common.js | 25 +++++++++++++++++++++++++ lib/gallery.show_full_size.js | 39 +++++---------------------------------- 2 files changed, 30 insertions(+), 34 deletions(-) diff --git a/lib/gallery.common.js b/lib/gallery.common.js index 06775d79..844e219b 100644 --- a/lib/gallery.common.js +++ b/lib/gallery.common.js @@ -125,5 +125,30 @@ ); }; + $.gallery_auto_fit_window = function(imageWidth, imageHeight) { + var size = $.gallery_get_viewport_size(); + var width = size.width() - 6, + height = size.height() - 6; + + var ratio = width / imageWidth; + imageWidth *= ratio; + imageHeight *= ratio; + + /* after scaling the width, check that the height fits */ + if (imageHeight > height) { + ratio = height / imageHeight; + imageWidth *= ratio; + imageHeight *= ratio; + } + + // handle the case where the calculation is almost zero (2.14e-14) + return { + top: Number((height - imageHeight) / 2), + left: Number((width - imageWidth) / 2), + width: Number(imageWidth), + height: Number(imageHeight) + }; + }; + })(jQuery); diff --git a/lib/gallery.show_full_size.js b/lib/gallery.show_full_size.js index c32195f6..2f365f0d 100644 --- a/lib/gallery.show_full_size.js +++ b/lib/gallery.show_full_size.js @@ -3,48 +3,19 @@ * @todo Move inline CSS out to external style sheet (theme style sheet) */ $.gallery_show_full_size = function(image_url, image_width, image_height) { - /* - * Calculate the size of the image panel based on the size of the image and the size of the - * window. Scale the image so the entire panel fits in the view port. - */ - function _auto_fit(imageWidth, imageHeight) { - // ui-dialog gives a padding of 2 pixels - var windowWidth = $(window).width() - 10; - var windowHeight = $(window).height() - 10; - - /* If the width is greater then scale the image width first */ - if (imageWidth > windowWidth) { - var ratio = windowWidth / imageWidth; - imageWidth *= ratio; - imageHeight *= ratio; - } - /* after scaling the width, check that the height fits */ - if (imageHeight > windowHeight) { - var ratio = windowHeight / imageHeight; - imageWidth *= ratio; - imageHeight *= ratio; - } - - // handle the case where the calculation is almost zero (2.14e-14) - return { - top: Number((windowHeight - imageHeight) / 2), - left: Number((windowWidth - imageWidth) / 2), - width: Number(imageWidth), - height: Number(imageHeight) - }; - } - var width = $(document).width(); var height = $(document).height(); + var size = $.gallery_get_viewport_size(); $("body").append('
                      '); - var image_size = _auto_fit(image_width, image_height); + var image_size = $.gallery_auto_fit_window(image_width, image_height); $("body").append('
                      Date: Thu, 20 Aug 2009 13:51:53 -0700 Subject: Add window resizing support. Just can't seem to get loading icon to show up --- modules/slideshow/js/slideshow.js | 106 ++++++++++++++++++-------------------- 1 file changed, 51 insertions(+), 55 deletions(-) diff --git a/modules/slideshow/js/slideshow.js b/modules/slideshow/js/slideshow.js index 0f04a206..1dffbf5a 100644 --- a/modules/slideshow/js/slideshow.js +++ b/modules/slideshow/js/slideshow.js @@ -2,11 +2,14 @@ $.gallery_slideshow = { interval: 4000, timer: null, + images: [], + current: -1, init: function(data) { var self = this; var size = $.gallery_get_viewport_size(); $("body").append( '
                      ' + + '
                       
                      ' + '
                      ' + '' + '' + @@ -19,24 +22,34 @@ // array of {url: xxx, width: nnn, height: nnn} for (var i=0; i < data.length; i++) { - var position = $.gallery_slideshow._autofit_image(data[i].width, data[i].height); $("#gSlideShowImages").append( - ''); - if (i == 0) { - $("#gSlideShowImages #img_0").load(function() { + ''); + $("#gSlideShowImages #img_" + i).load(function() { + $.gallery_slideshow.images.push("#" +$(this).attr("id")); + if ($.gallery_slideshow.images.length == 1) { $.gallery_slideshow._show_image(null); setTimeout(function() {$("#gSlideshowButtonPanel").hide();}, $.gallery_slideshow.interval); + } + }); + }; + $(window).resize(function() { + var size = $.gallery_get_viewport_size(); + $("#gSlideshowOverlay").width(size.width()).height(size.height()); + var current = $(".gSlideCurrent"); + var position = $.gallery_auto_fit_window(current.width(), current.height()); + $($.gallery_slideshow.images[$.gallery_slideshow.current].replace("img", "clone")) + .height(position.height).width(position.width).css({ + top: position.top, + left: position.left }); - } - } - }, + }); + }, close: function(event) { - $("#gSlideShowImages img.gSlideShowing").toggle(); $.gallery_slideshow.pause(); + $($.gallery_slideshow.images[$.gallery_slideshow.current].replace("img", "clone")).remove(); $("#gSlideshowOverlay").remove(); $("#gSlideShowImages").remove(); $("#gSlideshowButtonPanel").remove(); @@ -45,19 +58,18 @@ previous: function() { $.gallery_slideshow.pause(); - var next_image = $("#gSlideShowImages img.gSlideShowing").prev(); - if (next_image.length == 0) { - next_image = $("#gSlideShowImages img:last"); - } + $.gallery_slideshow.current--; + + $.gallery_slideshow.current = --$.gallery_slideshow.current < 0 ? + $.gallery_slideshow.images.length - 1 : $.gallery_slideshow.current; + var next_image = $($.gallery_slideshow.images[$.gallery_slideshow.current]); $.gallery_slideshow._show_image(next_image); }, next: function() { $.gallery_slideshow.pause(); - var next_image = $("#gSlideShowImages img.gSlideShowing").next(); - if (next_image.length == 0) { - next_image = $("#gSlideShowImages img:first"); - } + $.gallery_slideshow.current = ++$.gallery_slideshow.current % $.gallery_slideshow.images.length; + var next_image = $($.gallery_slideshow.images[$.gallery_slideshow.current]); $.gallery_slideshow._show_image(next_image); }, @@ -85,51 +97,35 @@ } }, - _autofit_image: function(imageWidth, imageHeight) { - var size = $.gallery_get_viewport_size(); - - var ratio = size.width() / imageWidth; - imageWidth *= ratio; - imageHeight *= ratio; - - /* after scaling the width, check that the height fits */ - if (imageHeight > size.height()) { - ratio = size.height() / imageHeight; - imageWidth *= ratio; - imageHeight *= ratio; - } - - // handle the case where the calculation is almost zero (2.14e-14) - return { - top: Number((size.height() - imageHeight) / 2), - left: Number((size.width() - imageWidth) / 2), - width: Number(imageWidth), - height: Number(imageHeight) - }; - }, - // If next_image is not null, then this a call from prev or next _show_image: function(next_image) { var reset_timer = false; + var previous = $.gallery_slideshow.current; if (next_image == null) { - next_image = $("#gSlideShowImages img.gSlideShowing").next(); - if (next_image.length == 0) { - next_image = $("#gSlideShowImages img:first"); - } + $.gallery_slideshow.current = ++$.gallery_slideshow.current % $.gallery_slideshow.images.length; + next_image = $($.gallery_slideshow.images[$.gallery_slideshow.current]); reset_timer = true; } - next_image.addClass("gSlideShowNextImage"); - var zIndex = parseInt(next_image.css("zIndex")); - next_image.css("zIndex", zIndex + 1); - next_image.fadeIn("slow", function() { - var current = $("#gSlideShowImages img.gSlideShowing"); - if (current.length) { - current.hide(); - current.removeClass("gSlideShowing"); + var position = $.gallery_auto_fit_window(next_image.width(), next_image.height()); + var clone = next_image.clone(); + + clone.attr("id", next_image.attr("id").replace("img", "clone")); + clone.height(position.height).width(position.width).css({ + marginTop: 0, marginLeft: 0, marginBottom: 0, marginRight: 0, + display: "none", + position: "absolute", + zIndex: zIndex + 1, + top: position.top + "px", + left: position.left + "px" + }); + + $("body").append(clone); + clone.fadeIn("slow", function() { + if (previous >= 0) { + $($.gallery_slideshow.images[previous].replace("img", "clone")).remove(); } - $(".gSlideShowNextImage").addClass("gSlideShowing").removeClass("gSlideShowNextImage") - .css("zIndex", zIndex); + clone.css("zIndex", zIndex); if (reset_timer) { $.gallery_slideshow.timer = setTimeout(function() {$.gallery_slideshow._show_image(null);}, -- cgit v1.2.3 From 457708311a466d8b116d5b28575be1bc3baad864 Mon Sep 17 00:00:00 2001 From: Chad Kieffer Date: Sun, 23 Aug 2009 14:58:26 -0600 Subject: Cut down on jittering of the context menu on open on resize view. --- lib/gallery.common.js | 12 ++++++++---- themes/default/js/.DS_Store | Bin 0 -> 6148 bytes 2 files changed, 8 insertions(+), 4 deletions(-) create mode 100644 themes/default/js/.DS_Store diff --git a/lib/gallery.common.js b/lib/gallery.common.js index 06775d79..16cb7ea2 100644 --- a/lib/gallery.common.js +++ b/lib/gallery.common.js @@ -112,15 +112,19 @@ }; $.fn.gallery_context_menu = function() { + var in_progress = 0; + $(".gContextMenu *").removeAttr('title'); $(".gContextMenu ul").hide(); $(".gContextMenu").hover( function() { - $(this).find("ul").slideDown("fast"); - $(this).find(".gDialogLink").gallery_dialog(); - $(this).find(".gAjaxLink").gallery_ajax(); + if (in_progress == 0) { + $(this).find("ul").slideDown("fast", function() { in_progress = 1; }); + $(this).find(".gDialogLink").gallery_dialog(); + $(this).find(".gAjaxLink").gallery_ajax(); + } }, function() { - $(this).find("ul").slideUp("slow"); + $(this).find("ul").slideUp("slow", function() { in_progress = 0; }); } ); }; diff --git a/themes/default/js/.DS_Store b/themes/default/js/.DS_Store new file mode 100644 index 00000000..5008ddfc Binary files /dev/null and b/themes/default/js/.DS_Store differ -- cgit v1.2.3 From deafc01c21887d8b699f26f9358a7acbf765151b Mon Sep 17 00:00:00 2001 From: Bharat Mediratta Date: Sun, 23 Aug 2009 15:05:18 -0700 Subject: Remove accidentally submitted .DS_Store file. --- themes/default/js/.DS_Store | Bin 6148 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 themes/default/js/.DS_Store diff --git a/themes/default/js/.DS_Store b/themes/default/js/.DS_Store deleted file mode 100644 index 5008ddfc..00000000 Binary files a/themes/default/js/.DS_Store and /dev/null differ -- cgit v1.2.3 From 0be38d143c44902f9482044da5f43c7a05134460 Mon Sep 17 00:00:00 2001 From: Andy Staudacher Date: Tue, 25 Aug 2009 13:32:57 -0700 Subject: Workaround to make G3 work with Turkish locale. Thanks to katpatuka for providing the fix. --- modules/gallery/libraries/I18n.php | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/modules/gallery/libraries/I18n.php b/modules/gallery/libraries/I18n.php index 03a6d8f6..b1b4298a 100644 --- a/modules/gallery/libraries/I18n.php +++ b/modules/gallery/libraries/I18n.php @@ -77,7 +77,12 @@ class I18n_Core { // TODO: See G2 for better fallack code. $locale_prefs = array($locale); $locale_prefs[] = 'en_US'; - setlocale(LC_ALL, $locale_prefs); + $new_locale = setlocale(LC_ALL, $locale_prefs); + if (is_string($new_locale) && strpos($new_locale, 'tr') === 0) { + // Make PHP 5 work with Turkish (the localization results are mixed though). + // Hack for http://bugs.php.net/18556 + setlocale(LC_CTYPE, 'C'); + } } return $this->_config['default_locale']; } -- cgit v1.2.3 From 940edac81c854227d1a25f482cb38c96b6937bb2 Mon Sep 17 00:00:00 2001 From: Tim Almdal Date: Thu, 27 Aug 2009 11:35:14 -0700 Subject: delete the simple slideshow --- modules/slideshow/controllers/slideshow.php | 64 ---------- modules/slideshow/css/buttons.png | Bin 3579 -> 0 bytes modules/slideshow/css/slideshow.css | 101 --------------- modules/slideshow/helpers/slideshow_event.php | 47 ------- modules/slideshow/helpers/slideshow_installer.php | 30 ----- modules/slideshow/helpers/slideshow_theme.php | 25 ---- modules/slideshow/js/slideshow.js | 145 ---------------------- modules/slideshow/module.info | 3 - 8 files changed, 415 deletions(-) delete mode 100644 modules/slideshow/controllers/slideshow.php delete mode 100644 modules/slideshow/css/buttons.png delete mode 100644 modules/slideshow/css/slideshow.css delete mode 100644 modules/slideshow/helpers/slideshow_event.php delete mode 100644 modules/slideshow/helpers/slideshow_installer.php delete mode 100644 modules/slideshow/helpers/slideshow_theme.php delete mode 100644 modules/slideshow/js/slideshow.js delete mode 100644 modules/slideshow/module.info diff --git a/modules/slideshow/controllers/slideshow.php b/modules/slideshow/controllers/slideshow.php deleted file mode 100644 index 8c4d1f46..00000000 --- a/modules/slideshow/controllers/slideshow.php +++ /dev/null @@ -1,64 +0,0 @@ -_build_image_list($item->children()))); - } - - function photo($item_id) { - $item = ORM::factory("item", $item_id); - access::required("view", $item); - - $images = $this->_build_image_list($item->parent()->children()); - $this_photo = array_search($item_id, array_keys($images)); - $images = array_merge(array_slice($images, $this_photo), array_slice($images, 0, $this_photo)); - - print json_encode($images); - } - - function tag($tag_id) { - $tag = ORM::factory("tag", $tag_id); - print json_encode(array_values($this->_build_image_list($tag->items()))); - } - - private function _build_image_list($children) { - $resizes = array(); - foreach ($children as $child) { - switch($child->type) { - case "album": - if (!empty($child->album_cover_item_id)) { - $cover = ORM::factory("item", $child->album_cover_item_id); - $resizes[$child->id] = array("url" => $cover->resize_url(), - "width" => $cover->resize_width, "height" => $cover->resize_height); - } - break; - case "photo": - $resizes[$child->id] = array("url" => $child->resize_url(), - "width" => $child->resize_width, "height" => $child->resize_height); - break; - } - } - - return $resizes; - } -} diff --git a/modules/slideshow/css/buttons.png b/modules/slideshow/css/buttons.png deleted file mode 100644 index 6fe50e1b..00000000 Binary files a/modules/slideshow/css/buttons.png and /dev/null differ diff --git a/modules/slideshow/css/slideshow.css b/modules/slideshow/css/slideshow.css deleted file mode 100644 index f635c244..00000000 --- a/modules/slideshow/css/slideshow.css +++ /dev/null @@ -1,101 +0,0 @@ -#gSlideshowOverlay { - border: none; - margin: 0; - padding: 0; - background-color: #000; - position: absolute; - top: 0px; - left: 0px; - width: 100%; - height: 100%; - opacity: 0.7; - filter: alpha(opacity=70); - -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; - -moz-background-inline-policy: -moz-initial; - z-index: 2001; -} - -#gSlideShowImages { - z-index: 2002; -} - -#gSlideShowImages img { - display: none; - float: left; - z-index: 2002; -} - -#gSlideshowButtonPanel { - bottom: .5em; - position: absolute; - width: 100%; - z-index: 2004; -} - -#gSlideshowButtonPanel div { - background-color: #000; - color: #fff; - filter: alpha(opacity=70); - height: 55px; - margin: 0 auto; - opacity: 0.7; - width: 232px; - z-index: 2004; -} - -#gSlideshowPrevious, -#gSlideshowPause, -#gSlideshowResume, -#gSlideshowResume, -#gSlideshowClose, -#gSlideshowNext { - background-image: url(buttons.png); - background-repeat: no-repeat; - display: block; - float: left; - height: 55px; - overflow: hidden; - text-indent: -99999px; - width: 58px; -} - -#gSlideshowPrevious { - background-position: 0 0; -} - -#gSlideshowPrevious:hover { - background-position: -58px 0; -} - -#gSlideshowPause { - background-position: -174px 0; -} - -#gSlideshowPause:hover { - background-position: -116px 0; -} - -#gSlideshowResume { - background-position: -290px 0; - display: none; -} - -#gSlideshowResume:hover { - background-position: -232px 0; -} - -#gSlideshowNext { - background-position: -406px 0; -} - -#gSlideshowNext:hover { - background-position: -348px 0; -} - -#gSlideshowClose { - background-position: -464px 0; -} - -#gSlideshowClose:hover { - background-position: -522px 0; -} diff --git a/modules/slideshow/helpers/slideshow_event.php b/modules/slideshow/helpers/slideshow_event.php deleted file mode 100644 index 926b4da1..00000000 --- a/modules/slideshow/helpers/slideshow_event.php +++ /dev/null @@ -1,47 +0,0 @@ -item(); - $menu->append(Menu::factory("link") - ->id("slideshow") - ->label(t("View slideshow")) - ->url(url::site("slideshow/album/{$item->id}")) - ->css_id("gSlideshowLink")); - } - - static function photo_menu($menu, $theme) { - $item = $theme->item(); - $menu->append(Menu::factory("link") - ->id("slideshow") - ->label(t("View slideshow")) - ->url(url::site("slideshow/photo/{$item->id}")) - ->css_id("gSlideshowLink")); - } - - static function tag_menu($menu, $theme) { - $tag = $theme->tag(); - $menu->append(Menu::factory("link") - ->id("slideshow") - ->label(t("View slideshow")) - ->url(url::site("slideshow/tag/{$tag->id}")) - ->css_id("gSlideshowLink")); - } -} diff --git a/modules/slideshow/helpers/slideshow_installer.php b/modules/slideshow/helpers/slideshow_installer.php deleted file mode 100644 index a71ea183..00000000 --- a/modules/slideshow/helpers/slideshow_installer.php +++ /dev/null @@ -1,30 +0,0 @@ -script("slideshow.js"); - $theme->css("slideshow.css"); - } -} diff --git a/modules/slideshow/js/slideshow.js b/modules/slideshow/js/slideshow.js deleted file mode 100644 index 1dffbf5a..00000000 --- a/modules/slideshow/js/slideshow.js +++ /dev/null @@ -1,145 +0,0 @@ -(function($) { - $.gallery_slideshow = { - interval: 4000, - timer: null, - images: [], - current: -1, - init: function(data) { - var self = this; - var size = $.gallery_get_viewport_size(); - $("body").append( - '
                      ' + - '
                       
                      ' + - '
                      ' + - '
                      '); - $().bind("mousemove", $.gallery_slideshow._mouse_over); - - // array of {url: xxx, width: nnn, height: nnn} - for (var i=0; i < data.length; i++) { - $("#gSlideShowImages").append( - ''); - $("#gSlideShowImages #img_" + i).load(function() { - $.gallery_slideshow.images.push("#" +$(this).attr("id")); - if ($.gallery_slideshow.images.length == 1) { - $.gallery_slideshow._show_image(null); - setTimeout(function() {$("#gSlideshowButtonPanel").hide();}, - $.gallery_slideshow.interval); - } - }); - }; - $(window).resize(function() { - var size = $.gallery_get_viewport_size(); - $("#gSlideshowOverlay").width(size.width()).height(size.height()); - var current = $(".gSlideCurrent"); - var position = $.gallery_auto_fit_window(current.width(), current.height()); - $($.gallery_slideshow.images[$.gallery_slideshow.current].replace("img", "clone")) - .height(position.height).width(position.width).css({ - top: position.top, - left: position.left - }); - }); - }, - - close: function(event) { - $.gallery_slideshow.pause(); - $($.gallery_slideshow.images[$.gallery_slideshow.current].replace("img", "clone")).remove(); - $("#gSlideshowOverlay").remove(); - $("#gSlideShowImages").remove(); - $("#gSlideshowButtonPanel").remove(); - $().unbind("mousemove", $.gallery_slideshow._mouse_over); - }, - - previous: function() { - $.gallery_slideshow.pause(); - $.gallery_slideshow.current--; - - $.gallery_slideshow.current = --$.gallery_slideshow.current < 0 ? - $.gallery_slideshow.images.length - 1 : $.gallery_slideshow.current; - var next_image = $($.gallery_slideshow.images[$.gallery_slideshow.current]); - $.gallery_slideshow._show_image(next_image); - }, - - next: function() { - $.gallery_slideshow.pause(); - $.gallery_slideshow.current = ++$.gallery_slideshow.current % $.gallery_slideshow.images.length; - var next_image = $($.gallery_slideshow.images[$.gallery_slideshow.current]); - $.gallery_slideshow._show_image(next_image); - }, - - pause: function() { - if ($.gallery_slideshow.timer) { - $("#gSlideshowPause").toggle(); - $("#gSlideshowResume").toggle(); - clearTimeout($.gallery_slideshow.timer); - $.gallery_slideshow.timer = null; - } - }, - - resume: function() { - $("#gSlideshowPause").toggle(); - $("#gSlideshowResume").toggle(); - $.gallery_slideshow._show_image(null); - }, - - _mouse_over: function(event) { - var size = $.gallery_get_viewport_size(); - if (event.pageY < size.height() && size.height() - 100 <= event.pageY) { - $("#gSlideshowButtonPanel").show(); - } else { - $("#gSlideshowButtonPanel").hide(); - } - }, - - // If next_image is not null, then this a call from prev or next - _show_image: function(next_image) { - var reset_timer = false; - var previous = $.gallery_slideshow.current; - if (next_image == null) { - $.gallery_slideshow.current = ++$.gallery_slideshow.current % $.gallery_slideshow.images.length; - next_image = $($.gallery_slideshow.images[$.gallery_slideshow.current]); - reset_timer = true; - } - var zIndex = parseInt(next_image.css("zIndex")); - var position = $.gallery_auto_fit_window(next_image.width(), next_image.height()); - var clone = next_image.clone(); - - clone.attr("id", next_image.attr("id").replace("img", "clone")); - clone.height(position.height).width(position.width).css({ - marginTop: 0, marginLeft: 0, marginBottom: 0, marginRight: 0, - display: "none", - position: "absolute", - zIndex: zIndex + 1, - top: position.top + "px", - left: position.left + "px" - }); - - $("body").append(clone); - clone.fadeIn("slow", function() { - if (previous >= 0) { - $($.gallery_slideshow.images[previous].replace("img", "clone")).remove(); - } - clone.css("zIndex", zIndex); - if (reset_timer) { - $.gallery_slideshow.timer = - setTimeout(function() {$.gallery_slideshow._show_image(null);}, - $.gallery_slideshow.interval); - } - }); - } - }; -})(jQuery); - -$(document).ready(function() { - $("#gSlideshowLink").click(function(event) { - event.preventDefault(); - $.get($(event.currentTarget).attr("href"), {}, $.gallery_slideshow.init, "json"); - return false; - }); -}); diff --git a/modules/slideshow/module.info b/modules/slideshow/module.info deleted file mode 100644 index b56eac81..00000000 --- a/modules/slideshow/module.info +++ /dev/null @@ -1,3 +0,0 @@ -name = "Slideshow" -description = "Allows users to view a slideshow of photos" -version = 2 -- cgit v1.2.3 From 5f86332db94966a635904e5f59cd00d1de9ccd13 Mon Sep 17 00:00:00 2001 From: Bharat Mediratta Date: Thu, 27 Aug 2009 11:41:19 -0700 Subject: Convert tabs to spaces. --- modules/gallery/libraries/I18n.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/modules/gallery/libraries/I18n.php b/modules/gallery/libraries/I18n.php index b1b4298a..d0531b9a 100644 --- a/modules/gallery/libraries/I18n.php +++ b/modules/gallery/libraries/I18n.php @@ -79,9 +79,9 @@ class I18n_Core { $locale_prefs[] = 'en_US'; $new_locale = setlocale(LC_ALL, $locale_prefs); if (is_string($new_locale) && strpos($new_locale, 'tr') === 0) { - // Make PHP 5 work with Turkish (the localization results are mixed though). - // Hack for http://bugs.php.net/18556 - setlocale(LC_CTYPE, 'C'); + // Make PHP 5 work with Turkish (the localization results are mixed though). + // Hack for http://bugs.php.net/18556 + setlocale(LC_CTYPE, 'C'); } } return $this->_config['default_locale']; @@ -183,7 +183,7 @@ class I18n_Core { static function is_plural_message($message) { return is_array($message); } - + private function interpolate($locale, $string, $values) { // TODO: Handle locale specific number formatting. -- cgit v1.2.3 From ddddfc5e8e505f83276acaa89057d5b9a9f6426f Mon Sep 17 00:00:00 2001 From: Chad Kieffer Date: Thu, 27 Aug 2009 14:27:49 -0600 Subject: Make the info block display 'File name', instead of 'Folder name' when showing a photo. Fixes #631 --- modules/info/views/info_block.html.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/info/views/info_block.html.php b/modules/info/views/info_block.html.php index f86ae39d..762e989b 100644 --- a/modules/info/views/info_block.html.php +++ b/modules/info/views/info_block.html.php @@ -12,7 +12,7 @@ id != 1): ?>
                    • - + page_type == 'album' ? t("Folder name:"): t("File name:"); ?> name) ?>
                    • -- cgit v1.2.3 From e586389f6573d4b4b817990064b61276d068b766 Mon Sep 17 00:00:00 2001 From: Bharat Mediratta Date: Thu, 27 Aug 2009 13:29:39 -0700 Subject: Don't ask for csrf when we're resetting passwords. They're not gonna have one. Duh! Fixes #642. --- modules/user/controllers/password.php | 2 -- 1 file changed, 2 deletions(-) diff --git a/modules/user/controllers/password.php b/modules/user/controllers/password.php index 2af1b879..7c432701 100644 --- a/modules/user/controllers/password.php +++ b/modules/user/controllers/password.php @@ -29,8 +29,6 @@ class Password_Controller extends Controller { } public function do_reset() { - access::verify_csrf(); - if (request::method() == "post") { $this->_change_password(); } else { -- cgit v1.2.3 From 75c098204f44538b79932f852469ae9d4338074c Mon Sep 17 00:00:00 2001 From: Bharat Mediratta Date: Thu, 27 Aug 2009 14:13:47 -0700 Subject: Add a comment about putting the mod_rewrite block into the apache config files, since .htaccess will get clobbered. --- .htaccess | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.htaccess b/.htaccess index 08b9c5bb..c3f94237 100644 --- a/.htaccess +++ b/.htaccess @@ -44,6 +44,11 @@ # # Then just use your Gallery 3 without the index.php in the url. # +# NOTE: future upgrades of Gallery 3 will overwrite this file! If you +# want these changes to be persistent, you should talk to your system +# administrator about putting this block into your Apache config +# files. +# # # RewriteEngine On # RewriteBase / -- cgit v1.2.3 From 88149a5afaa48711ccecda67036ec9a6755b9050 Mon Sep 17 00:00:00 2001 From: Bharat Mediratta Date: Thu, 27 Aug 2009 11:41:19 -0700 Subject: Convert tabs to spaces. --- modules/gallery/libraries/I18n.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/modules/gallery/libraries/I18n.php b/modules/gallery/libraries/I18n.php index b1b4298a..d0531b9a 100644 --- a/modules/gallery/libraries/I18n.php +++ b/modules/gallery/libraries/I18n.php @@ -79,9 +79,9 @@ class I18n_Core { $locale_prefs[] = 'en_US'; $new_locale = setlocale(LC_ALL, $locale_prefs); if (is_string($new_locale) && strpos($new_locale, 'tr') === 0) { - // Make PHP 5 work with Turkish (the localization results are mixed though). - // Hack for http://bugs.php.net/18556 - setlocale(LC_CTYPE, 'C'); + // Make PHP 5 work with Turkish (the localization results are mixed though). + // Hack for http://bugs.php.net/18556 + setlocale(LC_CTYPE, 'C'); } } return $this->_config['default_locale']; @@ -183,7 +183,7 @@ class I18n_Core { static function is_plural_message($message) { return is_array($message); } - + private function interpolate($locale, $string, $values) { // TODO: Handle locale specific number formatting. -- cgit v1.2.3 From db1f6e3e35485df041631e6d86baa17572ab7d4d Mon Sep 17 00:00:00 2001 From: Bharat Mediratta Date: Thu, 27 Aug 2009 13:29:39 -0700 Subject: Don't ask for csrf when we're resetting passwords. They're not gonna have one. Duh! Fixes #642. --- modules/user/controllers/password.php | 2 -- 1 file changed, 2 deletions(-) diff --git a/modules/user/controllers/password.php b/modules/user/controllers/password.php index 2af1b879..7c432701 100644 --- a/modules/user/controllers/password.php +++ b/modules/user/controllers/password.php @@ -29,8 +29,6 @@ class Password_Controller extends Controller { } public function do_reset() { - access::verify_csrf(); - if (request::method() == "post") { $this->_change_password(); } else { -- cgit v1.2.3 From 2c6328a47bedffe15791c518d6e9e42caedbbe3c Mon Sep 17 00:00:00 2001 From: Chad Kieffer Date: Thu, 27 Aug 2009 14:27:49 -0600 Subject: Make the info block display 'File name', instead of 'Folder name' when showing a photo. Fixes #631 --- modules/info/views/info_block.html.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/info/views/info_block.html.php b/modules/info/views/info_block.html.php index f86ae39d..762e989b 100644 --- a/modules/info/views/info_block.html.php +++ b/modules/info/views/info_block.html.php @@ -12,7 +12,7 @@ id != 1): ?>
                    • - + page_type == 'album' ? t("Folder name:"): t("File name:"); ?> name) ?>
                    • -- cgit v1.2.3 From ea717bbe2a75cb33c4c42d5a6574172bf81c14bf Mon Sep 17 00:00:00 2001 From: Bharat Mediratta Date: Thu, 27 Aug 2009 14:13:47 -0700 Subject: Add a comment about putting the mod_rewrite block into the apache config files, since .htaccess will get clobbered. --- .htaccess | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.htaccess b/.htaccess index 08b9c5bb..c3f94237 100644 --- a/.htaccess +++ b/.htaccess @@ -44,6 +44,11 @@ # # Then just use your Gallery 3 without the index.php in the url. # +# NOTE: future upgrades of Gallery 3 will overwrite this file! If you +# want these changes to be persistent, you should talk to your system +# administrator about putting this block into your Apache config +# files. +# # # RewriteEngine On # RewriteBase / -- cgit v1.2.3 From 980ee6b4b263481251c92da6f7382bc7235fb11c Mon Sep 17 00:00:00 2001 From: Bharat Mediratta Date: Thu, 27 Aug 2009 14:54:10 -0700 Subject: Revert "delete the simple slideshow" This reverts commit 940edac81c854227d1a25f482cb38c96b6937bb2. Revert "Add window resizing support. Just can't seem to get loading icon to show up" This reverts commit afd85945d7028cefd703c3f6bbebdf92f8e0477a. Revert "Resolve issues with show the wrong album when slideshow is invoked from a photo page. In addition, implement the slideshow based on tags." This reverts commit 152caf5195e3bbcdb353707fed5683ed07927f47. Revert "Initial commit of a basic slideshow" This reverts commit 5943761df282bfdfe68453de5c1682030006cd11. --- modules/slideshow/helpers/slideshow_event.php | 62 +++++++++++++++++++++++ modules/slideshow/helpers/slideshow_installer.php | 28 ++++++++++ modules/slideshow/helpers/slideshow_theme.php | 26 ++++++++++ modules/slideshow/module.info | 3 ++ 4 files changed, 119 insertions(+) create mode 100644 modules/slideshow/helpers/slideshow_event.php create mode 100644 modules/slideshow/helpers/slideshow_installer.php create mode 100644 modules/slideshow/helpers/slideshow_theme.php create mode 100644 modules/slideshow/module.info diff --git a/modules/slideshow/helpers/slideshow_event.php b/modules/slideshow/helpers/slideshow_event.php new file mode 100644 index 00000000..cf79f71a --- /dev/null +++ b/modules/slideshow/helpers/slideshow_event.php @@ -0,0 +1,62 @@ +deactivate)) { + site_status::warning( + t("The Slideshow module requires the RSS module. " . + "
                      Activate the RSS module now", + array("url" => url::site("admin/modules"))), + "slideshow_needs_rss"); + } else { + site_status::clear("slideshow_needs_rss"); + } + } + + static function album_menu($menu, $theme) { + $menu + ->append(Menu::factory("link") + ->id("slideshow") + ->label(t("View slideshow")) + ->url("javascript:PicLensLite.start(" . + "{maxScale:0,feedUrl:PicLensLite.indexFeeds()[0].url})") + ->css_id("gSlideshowLink")); + } + + static function photo_menu($menu, $theme) { + $menu + ->append(Menu::factory("link") + ->id("slideshow") + ->label(t("View slideshow")) + ->url("javascript:PicLensLite.start(" . + "{maxScale:0,feedUrl:PicLensLite.indexFeeds()[0].url})") + ->css_id("gSlideshowLink")); + } + + static function tag_menu($menu, $theme) { + $menu + ->append(Menu::factory("link") + ->id("slideshow") + ->label(t("View slideshow")) + ->url("javascript:PicLensLite.start(" . + "{maxScale:0,feedUrl:PicLensLite.indexFeeds()[0].url})") + ->css_id("gSlideshowLink")); + } +} diff --git a/modules/slideshow/helpers/slideshow_installer.php b/modules/slideshow/helpers/slideshow_installer.php new file mode 100644 index 00000000..cd1c6e05 --- /dev/null +++ b/modules/slideshow/helpers/slideshow_installer.php @@ -0,0 +1,28 @@ +"; + } +} diff --git a/modules/slideshow/module.info b/modules/slideshow/module.info new file mode 100644 index 00000000..6841199a --- /dev/null +++ b/modules/slideshow/module.info @@ -0,0 +1,3 @@ +name = "Slideshow" +description = "Allows users to view a slideshow of photos" +version = 1 -- cgit v1.2.3 From 56937cac5b00f1840e4d73dc840d015b80d75e41 Mon Sep 17 00:00:00 2001 From: Tim Almdal Date: Thu, 27 Aug 2009 15:04:14 -0700 Subject: Don't display the slideshow icon if there are no descendants. ticket #660 --- modules/slideshow/helpers/slideshow_event.php | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/modules/slideshow/helpers/slideshow_event.php b/modules/slideshow/helpers/slideshow_event.php index cf79f71a..1b881de4 100644 --- a/modules/slideshow/helpers/slideshow_event.php +++ b/modules/slideshow/helpers/slideshow_event.php @@ -31,13 +31,17 @@ class slideshow_event_Core { } static function album_menu($menu, $theme) { - $menu - ->append(Menu::factory("link") - ->id("slideshow") - ->label(t("View slideshow")) - ->url("javascript:PicLensLite.start(" . - "{maxScale:0,feedUrl:PicLensLite.indexFeeds()[0].url})") - ->css_id("gSlideshowLink")); + $descendants_count = ORM::factory("item", $theme->item->id) + ->descendants_count(array("type" => "photo")); + if ($descendants_count > 1) { + $menu + ->append(Menu::factory("link") + ->id("slideshow") + ->label(t("View slideshow")) + ->url("javascript:PicLensLite.start(" . + "{maxScale:0,feedUrl:PicLensLite.indexFeeds()[0].url})") + ->css_id("gSlideshowLink")); + } } static function photo_menu($menu, $theme) { -- cgit v1.2.3 From 84b018b08ddbaac2fe5688cfbd6b007ea72c019c Mon Sep 17 00:00:00 2001 From: Tim Almdal Date: Thu, 27 Aug 2009 15:22:27 -0700 Subject: Fix ticket #644 1) remove close button 2) extend the grey overlay to the document size 3) allow any keypress to close the fullize image 4) click on the fullsize will close --- lib/gallery.show_full_size.js | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/lib/gallery.show_full_size.js b/lib/gallery.show_full_size.js index 2f365f0d..1f74e6e2 100644 --- a/lib/gallery.show_full_size.js +++ b/lib/gallery.show_full_size.js @@ -10,7 +10,7 @@ $("body").append('
                      '); @@ -27,10 +27,14 @@ '
                      '); - $("#gFullsize").append(''); - $("#gFullsizeClose").click(function() { + //$("#gFullsize").append(''); + $("#gFullsize").click(function() { + $("#gFullsizeOverlay*").remove(); + $("#gFullsize").remove(); + }); + $().bind("keypress", function() { $("#gFullsizeOverlay*").remove(); $("#gFullsize").remove(); }); -- cgit v1.2.3 From bfc64685e4ae4bbd2c0308e9520194215ab51469 Mon Sep 17 00:00:00 2001 From: Tim Almdal Date: Thu, 27 Aug 2009 15:37:18 -0700 Subject: Allow clicking on the overlay to close the fullsize and remove some debug code --- lib/gallery.show_full_size.js | 35 +++++++++++++++-------------------- 1 file changed, 15 insertions(+), 20 deletions(-) diff --git a/lib/gallery.show_full_size.js b/lib/gallery.show_full_size.js index 1f74e6e2..7e826c32 100644 --- a/lib/gallery.show_full_size.js +++ b/lib/gallery.show_full_size.js @@ -27,27 +27,22 @@ '
                      '); - //$("#gFullsize").append(''); - $("#gFullsize").click(function() { - $("#gFullsizeOverlay*").remove(); - $("#gFullsize").remove(); - }); + $().click(function() { + $("#gFullsizeOverlay*").remove(); + $("#gFullsize").remove(); + }); $().bind("keypress", function() { - $("#gFullsizeOverlay*").remove(); - $("#gFullsize").remove(); - }); + $("#gFullsizeOverlay*").remove(); + $("#gFullsize").remove(); + }); $(window).resize(function() { - $("#gFullsizeOverlay").width($(document).width()) - .height($(document).height()); - image_size = $.gallery_auto_fit_window(image_width, image_height); - $("#gFullsize").height(image_size.height) - .width(image_size.width) - .css("top", image_size.top) - .css("left", image_size.left); - $("#gFullSizeImage").height(image_size.height) - .width(image_size.width); - }); + $("#gFullsizeOverlay").width($(document).width()).height($(document).height()); + image_size = $.gallery_auto_fit_window(image_width, image_height); + $("#gFullsize").height(image_size.height) + .width(image_size.width) + .css("top", image_size.top) + .css("left", image_size.left); + $("#gFullSizeImage").height(image_size.height).width(image_size.width); + }); }; })(jQuery); -- cgit v1.2.3 From 4828db003f3ee505eb9e6d056cdb142da34b78ff Mon Sep 17 00:00:00 2001 From: Bharat Mediratta Date: Thu, 27 Aug 2009 15:47:54 -0700 Subject: Remove 'ENGINE=InnoDB' specification from tables that we create. Use the system's default table specification. Fixes ticket #597. --- installer/install.sql | 44 +++++++++++----------- modules/comment/helpers/comment_installer.php | 2 +- modules/digibug/helpers/digibug_installer.php | 2 +- modules/exif/helpers/exif_installer.php | 2 +- modules/g2_import/helpers/g2_import_installer.php | 2 +- modules/gallery/controllers/packager.php | 4 ++ modules/gallery/helpers/gallery_installer.php | 32 ++++++++-------- .../helpers/notification_installer.php | 4 +- modules/search/helpers/search_installer.php | 2 +- .../server_add/helpers/server_add_installer.php | 4 +- modules/tag/helpers/tag_installer.php | 4 +- modules/user/helpers/user_installer.php | 6 +-- modules/watermark/helpers/watermark_installer.php | 2 +- 13 files changed, 57 insertions(+), 53 deletions(-) diff --git a/installer/install.sql b/installer/install.sql index 48b504ba..21464379 100755 --- a/installer/install.sql +++ b/installer/install.sql @@ -11,7 +11,7 @@ CREATE TABLE {access_caches} ( `edit_2` binary(1) NOT NULL default '0', `add_2` binary(1) NOT NULL default '0', PRIMARY KEY (`id`) -) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8; +) AUTO_INCREMENT=2 DEFAULT CHARSET=utf8; SET character_set_client = @saved_cs_client; INSERT INTO {access_caches} VALUES (1,1,'1','0','0','1','0','0'); DROP TABLE IF EXISTS {access_intents}; @@ -29,7 +29,7 @@ CREATE TABLE {access_intents} ( `edit_2` binary(1) default NULL, `add_2` binary(1) default NULL, PRIMARY KEY (`id`) -) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8; +) AUTO_INCREMENT=2 DEFAULT CHARSET=utf8; SET character_set_client = @saved_cs_client; INSERT INTO {access_intents} VALUES (1,1,'1','1','0','0','1','1','0','0'); DROP TABLE IF EXISTS {caches}; @@ -43,7 +43,7 @@ CREATE TABLE {caches} ( `cache` longblob, PRIMARY KEY (`id`), KEY `tags` (`tags`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8; +) DEFAULT CHARSET=utf8; SET character_set_client = @saved_cs_client; DROP TABLE IF EXISTS {comments}; SET @saved_cs_client = @@character_set_client; @@ -72,7 +72,7 @@ CREATE TABLE {comments} ( `text` text, `updated` int(9) NOT NULL, PRIMARY KEY (`id`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8; +) DEFAULT CHARSET=utf8; SET character_set_client = @saved_cs_client; DROP TABLE IF EXISTS {graphics_rules}; SET @saved_cs_client = @@character_set_client; @@ -86,7 +86,7 @@ CREATE TABLE {graphics_rules} ( `priority` int(9) NOT NULL, `target` varchar(32) NOT NULL, PRIMARY KEY (`id`) -) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8; +) AUTO_INCREMENT=3 DEFAULT CHARSET=utf8; SET character_set_client = @saved_cs_client; INSERT INTO {graphics_rules} VALUES (1,1,'a:3:{s:5:\"width\";i:200;s:6:\"height\";i:200;s:6:\"master\";i:2;}','gallery','resize',100,'thumb'); INSERT INTO {graphics_rules} VALUES (2,1,'a:3:{s:5:\"width\";i:640;s:6:\"height\";i:480;s:6:\"master\";i:2;}','gallery','resize',100,'resize'); @@ -99,7 +99,7 @@ CREATE TABLE {groups} ( `special` tinyint(1) default '0', PRIMARY KEY (`id`), UNIQUE KEY `name` (`name`) -) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8; +) AUTO_INCREMENT=3 DEFAULT CHARSET=utf8; SET character_set_client = @saved_cs_client; INSERT INTO {groups} VALUES (1,'Everybody',1); INSERT INTO {groups} VALUES (2,'Registered Users',1); @@ -111,7 +111,7 @@ CREATE TABLE {groups_users} ( `user_id` int(9) NOT NULL, PRIMARY KEY (`group_id`,`user_id`), UNIQUE KEY `user_id` (`user_id`,`group_id`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8; +) DEFAULT CHARSET=utf8; SET character_set_client = @saved_cs_client; INSERT INTO {groups_users} VALUES (1,1); INSERT INTO {groups_users} VALUES (1,2); @@ -129,7 +129,7 @@ CREATE TABLE {incoming_translations} ( PRIMARY KEY (`id`), UNIQUE KEY `key` (`key`,`locale`), KEY `locale_key` (`locale`,`key`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8; +) DEFAULT CHARSET=utf8; SET character_set_client = @saved_cs_client; DROP TABLE IF EXISTS {items}; SET @saved_cs_client = @@character_set_client; @@ -171,7 +171,7 @@ CREATE TABLE {items} ( KEY `type` (`type`), KEY `random` (`rand_key`), KEY `weight` (`weight`) -) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8; +) AUTO_INCREMENT=2 DEFAULT CHARSET=utf8; SET character_set_client = @saved_cs_client; INSERT INTO {items} VALUES (1,NULL,NULL,UNIX_TIMESTAMP(),'',NULL,1,1,NULL,NULL,NULL,0,NULL,'',1,NULL,NULL,2,'weight','ASC',1,NULL,NULL,'Gallery','album',UNIX_TIMESTAMP(),0,1,NULL,'1','1'); DROP TABLE IF EXISTS {items_tags}; @@ -184,7 +184,7 @@ CREATE TABLE {items_tags} ( PRIMARY KEY (`id`), KEY `tag_id` (`tag_id`,`id`), KEY `item_id` (`item_id`,`id`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8; +) DEFAULT CHARSET=utf8; SET character_set_client = @saved_cs_client; DROP TABLE IF EXISTS {logs}; SET @saved_cs_client = @@character_set_client; @@ -200,7 +200,7 @@ CREATE TABLE {logs} ( `url` varchar(255) default NULL, `user_id` int(9) default '0', PRIMARY KEY (`id`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8; +) DEFAULT CHARSET=utf8; SET character_set_client = @saved_cs_client; DROP TABLE IF EXISTS {messages}; SET @saved_cs_client = @@character_set_client; @@ -212,7 +212,7 @@ CREATE TABLE {messages} ( `value` varchar(255) default NULL, PRIMARY KEY (`id`), UNIQUE KEY `key` (`key`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8; +) DEFAULT CHARSET=utf8; SET character_set_client = @saved_cs_client; DROP TABLE IF EXISTS {modules}; SET @saved_cs_client = @@character_set_client; @@ -224,7 +224,7 @@ CREATE TABLE {modules} ( `version` int(9) default NULL, PRIMARY KEY (`id`), UNIQUE KEY `name` (`name`) -) ENGINE=InnoDB AUTO_INCREMENT=10 DEFAULT CHARSET=utf8; +) AUTO_INCREMENT=10 DEFAULT CHARSET=utf8; SET character_set_client = @saved_cs_client; INSERT INTO {modules} VALUES (1,1,'gallery',10); INSERT INTO {modules} VALUES (2,1,'user',1); @@ -248,7 +248,7 @@ CREATE TABLE {outgoing_translations} ( PRIMARY KEY (`id`), UNIQUE KEY `key` (`key`,`locale`), KEY `locale_key` (`locale`,`key`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8; +) DEFAULT CHARSET=utf8; SET character_set_client = @saved_cs_client; DROP TABLE IF EXISTS {permissions}; SET @saved_cs_client = @@character_set_client; @@ -259,7 +259,7 @@ CREATE TABLE {permissions} ( `name` varchar(64) default NULL, PRIMARY KEY (`id`), UNIQUE KEY `name` (`name`) -) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8; +) AUTO_INCREMENT=5 DEFAULT CHARSET=utf8; SET character_set_client = @saved_cs_client; INSERT INTO {permissions} VALUES (1,'View','view'); INSERT INTO {permissions} VALUES (2,'View Full Size','view_full'); @@ -276,7 +276,7 @@ CREATE TABLE {search_records} ( PRIMARY KEY (`id`), KEY `item_id` (`item_id`), FULLTEXT KEY `data` (`data`) -) ENGINE=MyISAM AUTO_INCREMENT=2 DEFAULT CHARSET=utf8; +) AUTO_INCREMENT=2 DEFAULT CHARSET=utf8; SET character_set_client = @saved_cs_client; INSERT INTO {search_records} VALUES (1,1,0,' Gallery'); DROP TABLE IF EXISTS {sessions}; @@ -287,7 +287,7 @@ CREATE TABLE {sessions} ( `data` text NOT NULL, `last_activity` int(10) unsigned NOT NULL, PRIMARY KEY (`session_id`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8; +) DEFAULT CHARSET=utf8; SET character_set_client = @saved_cs_client; DROP TABLE IF EXISTS {tags}; SET @saved_cs_client = @@character_set_client; @@ -298,7 +298,7 @@ CREATE TABLE {tags} ( `count` int(10) unsigned NOT NULL default '0', PRIMARY KEY (`id`), UNIQUE KEY `name` (`name`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8; +) DEFAULT CHARSET=utf8; SET character_set_client = @saved_cs_client; DROP TABLE IF EXISTS {tasks}; SET @saved_cs_client = @@character_set_client; @@ -316,7 +316,7 @@ CREATE TABLE {tasks} ( `updated` int(9) default NULL, PRIMARY KEY (`id`), KEY `owner_id` (`owner_id`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8; +) DEFAULT CHARSET=utf8; SET character_set_client = @saved_cs_client; DROP TABLE IF EXISTS {themes}; SET @saved_cs_client = @@character_set_client; @@ -327,7 +327,7 @@ CREATE TABLE {themes} ( `version` int(9) default NULL, PRIMARY KEY (`id`), UNIQUE KEY `name` (`name`) -) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8; +) AUTO_INCREMENT=3 DEFAULT CHARSET=utf8; SET character_set_client = @saved_cs_client; INSERT INTO {themes} VALUES (1,'default',1); INSERT INTO {themes} VALUES (2,'admin_default',1); @@ -350,7 +350,7 @@ CREATE TABLE {users} ( PRIMARY KEY (`id`), UNIQUE KEY `name` (`name`), UNIQUE KEY `hash` (`hash`) -) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8; +) AUTO_INCREMENT=3 DEFAULT CHARSET=utf8; SET character_set_client = @saved_cs_client; INSERT INTO {users} VALUES (1,'guest','Guest User','',0,0,NULL,0,1,NULL,NULL,NULL); INSERT INTO {users} VALUES (2,'admin','Gallery Administrator','',0,0,NULL,1,0,NULL,NULL,NULL); @@ -364,7 +364,7 @@ CREATE TABLE {vars} ( `value` text, PRIMARY KEY (`id`), UNIQUE KEY `module_name` (`module_name`,`name`) -) ENGINE=InnoDB AUTO_INCREMENT=27 DEFAULT CHARSET=utf8; +) AUTO_INCREMENT=27 DEFAULT CHARSET=utf8; SET character_set_client = @saved_cs_client; INSERT INTO {vars} VALUES (1,'gallery','active_site_theme','default'); INSERT INTO {vars} VALUES (2,'gallery','active_admin_theme','admin_default'); diff --git a/modules/comment/helpers/comment_installer.php b/modules/comment/helpers/comment_installer.php index edf2427c..80594c16 100644 --- a/modules/comment/helpers/comment_installer.php +++ b/modules/comment/helpers/comment_installer.php @@ -44,7 +44,7 @@ class comment_installer { `text` text, `updated` int(9) NOT NULL, PRIMARY KEY (`id`)) - ENGINE=InnoDB DEFAULT CHARSET=utf8;"); + DEFAULT CHARSET=utf8;"); block_manager::add("dashboard_center", "comment", "recent_comments"); module::set_var("comment", "spam_caught", 0); diff --git a/modules/digibug/helpers/digibug_installer.php b/modules/digibug/helpers/digibug_installer.php index 1cd78b44..7e8145d2 100644 --- a/modules/digibug/helpers/digibug_installer.php +++ b/modules/digibug/helpers/digibug_installer.php @@ -26,7 +26,7 @@ class digibug_installer { `request_date` TIMESTAMP NOT NULL DEFAULT current_timestamp, `item_id` int(9) NOT NULL, PRIMARY KEY (`id`)) - ENGINE=InnoDB DEFAULT CHARSET=utf8;"); + DEFAULT CHARSET=utf8;"); module::set_var("digibug", "company_id", "3153"); module::set_var("digibug", "event_id", "8491"); diff --git a/modules/exif/helpers/exif_installer.php b/modules/exif/helpers/exif_installer.php index 0233f2bb..66226061 100644 --- a/modules/exif/helpers/exif_installer.php +++ b/modules/exif/helpers/exif_installer.php @@ -28,7 +28,7 @@ class exif_installer { `dirty` BOOLEAN default 1, PRIMARY KEY (`id`), KEY(`item_id`)) - ENGINE=InnoDB DEFAULT CHARSET=utf8;"); + DEFAULT CHARSET=utf8;"); module::set_version("exif", 1); } diff --git a/modules/g2_import/helpers/g2_import_installer.php b/modules/g2_import/helpers/g2_import_installer.php index 0f87da6c..feacb518 100644 --- a/modules/g2_import/helpers/g2_import_installer.php +++ b/modules/g2_import/helpers/g2_import_installer.php @@ -26,7 +26,7 @@ class g2_import_installer { `g3_id` int(9) NOT NULL, PRIMARY KEY (`id`), KEY (`g2_id`)) - ENGINE=InnoDB DEFAULT CHARSET=utf8;"); + DEFAULT CHARSET=utf8;"); module::set_version("g2_import", 1); mkdir(VARPATH . "modules/g2_import"); diff --git a/modules/gallery/controllers/packager.php b/modules/gallery/controllers/packager.php index 7b4d68f6..fbb1d07d 100644 --- a/modules/gallery/controllers/packager.php +++ b/modules/gallery/controllers/packager.php @@ -123,6 +123,10 @@ class Packager_Controller extends Controller { // Normalize dates $line = preg_replace("/,$root_created_timestamp,/", ",UNIX_TIMESTAMP(),", $line); $line = preg_replace("/,$root_updated_timestamp,/", ",UNIX_TIMESTAMP(),", $line); + + // Remove ENGINE= specifications + $line = preg_replace("/ENGINE=\S+ /", "", $line); + $buf .= $line; } $fd = fopen($sql_file, "wb"); diff --git a/modules/gallery/helpers/gallery_installer.php b/modules/gallery/helpers/gallery_installer.php index d12dad70..a212ef85 100644 --- a/modules/gallery/helpers/gallery_installer.php +++ b/modules/gallery/helpers/gallery_installer.php @@ -24,13 +24,13 @@ class gallery_installer { `id` int(9) NOT NULL auto_increment, `item_id` int(9), PRIMARY KEY (`id`)) - ENGINE=InnoDB DEFAULT CHARSET=utf8;"); + DEFAULT CHARSET=utf8;"); $db->query("CREATE TABLE {access_intents} ( `id` int(9) NOT NULL auto_increment, `item_id` int(9), PRIMARY KEY (`id`)) - ENGINE=InnoDB DEFAULT CHARSET=utf8;"); + DEFAULT CHARSET=utf8;"); $db->query("CREATE TABLE {caches} ( `id` int(9) NOT NULL auto_increment, @@ -40,7 +40,7 @@ class gallery_installer { `cache` longblob, PRIMARY KEY (`id`), KEY (`tags`)) - ENGINE=InnoDB DEFAULT CHARSET=utf8;"); + DEFAULT CHARSET=utf8;"); $db->query("CREATE TABLE {graphics_rules} ( `id` int(9) NOT NULL auto_increment, @@ -51,7 +51,7 @@ class gallery_installer { `priority` int(9) NOT NULL, `target` varchar(32) NOT NULL, PRIMARY KEY (`id`)) - ENGINE=InnoDB DEFAULT CHARSET=utf8;"); + DEFAULT CHARSET=utf8;"); $db->query("CREATE TABLE {incoming_translations} ( `id` int(9) NOT NULL auto_increment, @@ -63,7 +63,7 @@ class gallery_installer { PRIMARY KEY (`id`), UNIQUE KEY(`key`, `locale`), KEY `locale_key` (`locale`, `key`)) - ENGINE=InnoDB DEFAULT CHARSET=utf8;"); + DEFAULT CHARSET=utf8;"); $db->query("CREATE TABLE {items} ( `id` int(9) NOT NULL auto_increment, @@ -100,7 +100,7 @@ class gallery_installer { KEY `type` (`type`), KEY `random` (`rand_key`), KEY `weight` (`weight` DESC)) - ENGINE=InnoDB DEFAULT CHARSET=utf8;"); + DEFAULT CHARSET=utf8;"); $db->query("CREATE TABLE {logs} ( `id` int(9) NOT NULL auto_increment, @@ -113,7 +113,7 @@ class gallery_installer { `url` varchar(255) default NULL, `user_id` int(9) default 0, PRIMARY KEY (`id`)) - ENGINE=InnoDB DEFAULT CHARSET=utf8;"); + DEFAULT CHARSET=utf8;"); $db->query("CREATE TABLE {messages} ( `id` int(9) NOT NULL auto_increment, @@ -122,7 +122,7 @@ class gallery_installer { `value` varchar(255) default NULL, PRIMARY KEY (`id`), UNIQUE KEY(`key`)) - ENGINE=InnoDB DEFAULT CHARSET=utf8;"); + DEFAULT CHARSET=utf8;"); $db->query("CREATE TABLE {modules} ( `id` int(9) NOT NULL auto_increment, @@ -131,7 +131,7 @@ class gallery_installer { `version` int(9) default NULL, PRIMARY KEY (`id`), UNIQUE KEY(`name`)) - ENGINE=InnoDB DEFAULT CHARSET=utf8;"); + DEFAULT CHARSET=utf8;"); $db->query("CREATE TABLE {outgoing_translations} ( `id` int(9) NOT NULL auto_increment, @@ -143,7 +143,7 @@ class gallery_installer { PRIMARY KEY (`id`), UNIQUE KEY(`key`, `locale`), KEY `locale_key` (`locale`, `key`)) - ENGINE=InnoDB DEFAULT CHARSET=utf8;"); + DEFAULT CHARSET=utf8;"); $db->query("CREATE TABLE {permissions} ( `id` int(9) NOT NULL auto_increment, @@ -151,14 +151,14 @@ class gallery_installer { `name` varchar(64) default NULL, PRIMARY KEY (`id`), UNIQUE KEY(`name`)) - ENGINE=InnoDB DEFAULT CHARSET=utf8;"); + DEFAULT CHARSET=utf8;"); $db->query("CREATE TABLE {sessions} ( `session_id` varchar(127) NOT NULL, `data` text NOT NULL, `last_activity` int(10) UNSIGNED NOT NULL, PRIMARY KEY (`session_id`)) - ENGINE=InnoDB DEFAULT CHARSET=utf8;"); + DEFAULT CHARSET=utf8;"); $db->query("CREATE TABLE {tasks} ( `id` int(9) NOT NULL auto_increment, @@ -173,7 +173,7 @@ class gallery_installer { `updated` int(9) default NULL, PRIMARY KEY (`id`), KEY (`owner_id`)) - ENGINE=InnoDB DEFAULT CHARSET=utf8;"); + DEFAULT CHARSET=utf8;"); $db->query("CREATE TABLE {themes} ( `id` int(9) NOT NULL auto_increment, @@ -181,7 +181,7 @@ class gallery_installer { `version` int(9) default NULL, PRIMARY KEY (`id`), UNIQUE KEY(`name`)) - ENGINE=InnoDB DEFAULT CHARSET=utf8;"); + DEFAULT CHARSET=utf8;"); $db->query("CREATE TABLE {vars} ( `id` int(9) NOT NULL auto_increment, @@ -190,7 +190,7 @@ class gallery_installer { `value` text, PRIMARY KEY (`id`), UNIQUE KEY(`module_name`, `name`)) - ENGINE=InnoDB DEFAULT CHARSET=utf8;"); + DEFAULT CHARSET=utf8;"); foreach (array("albums", "logs", "modules", "resizes", "thumbs", "tmp", "uploads") as $dir) { @mkdir(VARPATH . $dir); @@ -284,7 +284,7 @@ class gallery_installer { `cache` text, PRIMARY KEY (`id`), KEY (`tags`)) - ENGINE=InnoDB DEFAULT CHARSET=utf8;"); + DEFAULT CHARSET=utf8;"); module::set_version("gallery", $version = 4); } diff --git a/modules/notification/helpers/notification_installer.php b/modules/notification/helpers/notification_installer.php index 3d450258..aa2e09f7 100644 --- a/modules/notification/helpers/notification_installer.php +++ b/modules/notification/helpers/notification_installer.php @@ -27,14 +27,14 @@ class notification_installer { PRIMARY KEY (`id`), UNIQUE KEY (`item_id`, `user_id`), UNIQUE KEY (`user_id`, `item_id`)) - ENGINE=InnoDB DEFAULT CHARSET=utf8;"); + DEFAULT CHARSET=utf8;"); $db->query("CREATE TABLE IF NOT EXISTS {pending_notifications} ( `id` int(9) NOT NULL auto_increment, `email` varchar(128) NOT NULL, `subject` varchar(255) NOT NULL, `text` text, PRIMARY KEY (`id`)) - ENGINE=InnoDB DEFAULT CHARSET=utf8;"); + DEFAULT CHARSET=utf8;"); module::set_version("notification", 1); } diff --git a/modules/search/helpers/search_installer.php b/modules/search/helpers/search_installer.php index cd253be4..10d8211f 100644 --- a/modules/search/helpers/search_installer.php +++ b/modules/search/helpers/search_installer.php @@ -28,7 +28,7 @@ class search_installer { PRIMARY KEY (`id`), KEY(`item_id`), FULLTEXT INDEX (`data`)) - ENGINE=MyISAM DEFAULT CHARSET=utf8;"); + DEFAULT CHARSET=utf8;"); module::set_version("search", 1); } diff --git a/modules/server_add/helpers/server_add_installer.php b/modules/server_add/helpers/server_add_installer.php index cd278eb7..c3c1572d 100644 --- a/modules/server_add/helpers/server_add_installer.php +++ b/modules/server_add/helpers/server_add_installer.php @@ -27,7 +27,7 @@ class server_add_installer { `parent_id` int(9), `task_id` int(9) NOT NULL, PRIMARY KEY (`id`)) - ENGINE=InnoDB DEFAULT CHARSET=utf8;"); + DEFAULT CHARSET=utf8;"); module::set_version("server_add", 3); server_add::check_config(); } @@ -40,7 +40,7 @@ class server_add_installer { `task_id` int(9) NOT NULL, `file` varchar(255) NOT NULL, PRIMARY KEY (`id`)) - ENGINE=InnoDB DEFAULT CHARSET=utf8;"); + DEFAULT CHARSET=utf8;"); module::set_version("server_add", $version = 2); } diff --git a/modules/tag/helpers/tag_installer.php b/modules/tag/helpers/tag_installer.php index 3c16e3f3..bcb830e4 100644 --- a/modules/tag/helpers/tag_installer.php +++ b/modules/tag/helpers/tag_installer.php @@ -26,7 +26,7 @@ class tag_installer { `count` int(10) unsigned NOT NULL DEFAULT 0, PRIMARY KEY (`id`), UNIQUE KEY(`name`)) - ENGINE=InnoDB DEFAULT CHARSET=utf8;"); + DEFAULT CHARSET=utf8;"); $db->query("CREATE TABLE IF NOT EXISTS {items_tags} ( `id` int(9) NOT NULL auto_increment, @@ -35,7 +35,7 @@ class tag_installer { PRIMARY KEY (`id`), KEY(`tag_id`, `id`), KEY(`item_id`, `id`)) - ENGINE=InnoDB DEFAULT CHARSET=utf8;"); + DEFAULT CHARSET=utf8;"); module::set_version("tag", 1); } diff --git a/modules/user/helpers/user_installer.php b/modules/user/helpers/user_installer.php index 1959d038..8ef4f13d 100644 --- a/modules/user/helpers/user_installer.php +++ b/modules/user/helpers/user_installer.php @@ -36,7 +36,7 @@ class user_installer { PRIMARY KEY (`id`), UNIQUE KEY(`hash`), UNIQUE KEY(`name`)) - ENGINE=InnoDB DEFAULT CHARSET=utf8;"); + DEFAULT CHARSET=utf8;"); $db->query("CREATE TABLE IF NOT EXISTS {groups} ( `id` int(9) NOT NULL auto_increment, @@ -44,14 +44,14 @@ class user_installer { `special` BOOLEAN default 0, PRIMARY KEY (`id`), UNIQUE KEY(`name`)) - ENGINE=InnoDB DEFAULT CHARSET=utf8;"); + DEFAULT CHARSET=utf8;"); $db->query("CREATE TABLE IF NOT EXISTS {groups_users} ( `group_id` int(9) NOT NULL, `user_id` int(9) NOT NULL, PRIMARY KEY (`group_id`, `user_id`), UNIQUE KEY(`user_id`, `group_id`)) - ENGINE=InnoDB DEFAULT CHARSET=utf8;"); + DEFAULT CHARSET=utf8;"); $everybody = group::create("Everybody"); $everybody->special = true; diff --git a/modules/watermark/helpers/watermark_installer.php b/modules/watermark/helpers/watermark_installer.php index 705b89d4..b3e91044 100644 --- a/modules/watermark/helpers/watermark_installer.php +++ b/modules/watermark/helpers/watermark_installer.php @@ -30,7 +30,7 @@ class watermark_installer { `mime_type` varchar(64) default NULL, PRIMARY KEY (`id`), UNIQUE KEY(`name`)) - ENGINE=InnoDB DEFAULT CHARSET=utf8;"); + DEFAULT CHARSET=utf8;"); @mkdir(VARPATH . "modules/watermark"); module::set_version("watermark", 1); -- cgit v1.2.3 From 98e9a96ba4d2419e02717369be8c0d886bc35ef7 Mon Sep 17 00:00:00 2001 From: Bharat Mediratta Date: Thu, 27 Aug 2009 16:10:38 -0700 Subject: Don't display the slideshow icon if there are no descendants. ticket #660 Conflicts: modules/slideshow/helpers/slideshow_event.php --- modules/slideshow/helpers/slideshow_event.php | 34 +++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/modules/slideshow/helpers/slideshow_event.php b/modules/slideshow/helpers/slideshow_event.php index c6cd7dc7..1b881de4 100644 --- a/modules/slideshow/helpers/slideshow_event.php +++ b/modules/slideshow/helpers/slideshow_event.php @@ -29,4 +29,38 @@ class slideshow_event_Core { site_status::clear("slideshow_needs_rss"); } } + + static function album_menu($menu, $theme) { + $descendants_count = ORM::factory("item", $theme->item->id) + ->descendants_count(array("type" => "photo")); + if ($descendants_count > 1) { + $menu + ->append(Menu::factory("link") + ->id("slideshow") + ->label(t("View slideshow")) + ->url("javascript:PicLensLite.start(" . + "{maxScale:0,feedUrl:PicLensLite.indexFeeds()[0].url})") + ->css_id("gSlideshowLink")); + } + } + + static function photo_menu($menu, $theme) { + $menu + ->append(Menu::factory("link") + ->id("slideshow") + ->label(t("View slideshow")) + ->url("javascript:PicLensLite.start(" . + "{maxScale:0,feedUrl:PicLensLite.indexFeeds()[0].url})") + ->css_id("gSlideshowLink")); + } + + static function tag_menu($menu, $theme) { + $menu + ->append(Menu::factory("link") + ->id("slideshow") + ->label(t("View slideshow")) + ->url("javascript:PicLensLite.start(" . + "{maxScale:0,feedUrl:PicLensLite.indexFeeds()[0].url})") + ->css_id("gSlideshowLink")); + } } -- cgit v1.2.3 From 5db90d432de180b361b2160bc48cb7bafd6fdaf1 Mon Sep 17 00:00:00 2001 From: Tim Almdal Date: Thu, 27 Aug 2009 15:22:27 -0700 Subject: Fix ticket #644 1) remove close button 2) extend the grey overlay to the document size 3) allow any keypress to close the fullize image 4) click on the fullsize will close --- lib/gallery.show_full_size.js | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/lib/gallery.show_full_size.js b/lib/gallery.show_full_size.js index 2f365f0d..1f74e6e2 100644 --- a/lib/gallery.show_full_size.js +++ b/lib/gallery.show_full_size.js @@ -10,7 +10,7 @@ $("body").append('
                      '); @@ -27,10 +27,14 @@ '
                      '); - $("#gFullsize").append(''); - $("#gFullsizeClose").click(function() { + //$("#gFullsize").append(''); + $("#gFullsize").click(function() { + $("#gFullsizeOverlay*").remove(); + $("#gFullsize").remove(); + }); + $().bind("keypress", function() { $("#gFullsizeOverlay*").remove(); $("#gFullsize").remove(); }); -- cgit v1.2.3 From e0e430bd84d8c82eb425c0bc828dae2b9c0d86be Mon Sep 17 00:00:00 2001 From: Tim Almdal Date: Thu, 27 Aug 2009 15:37:18 -0700 Subject: Allow clicking on the overlay to close the fullsize and remove some debug code --- lib/gallery.show_full_size.js | 35 +++++++++++++++-------------------- 1 file changed, 15 insertions(+), 20 deletions(-) diff --git a/lib/gallery.show_full_size.js b/lib/gallery.show_full_size.js index 1f74e6e2..7e826c32 100644 --- a/lib/gallery.show_full_size.js +++ b/lib/gallery.show_full_size.js @@ -27,27 +27,22 @@ '
                      '); - //$("#gFullsize").append(''); - $("#gFullsize").click(function() { - $("#gFullsizeOverlay*").remove(); - $("#gFullsize").remove(); - }); + $().click(function() { + $("#gFullsizeOverlay*").remove(); + $("#gFullsize").remove(); + }); $().bind("keypress", function() { - $("#gFullsizeOverlay*").remove(); - $("#gFullsize").remove(); - }); + $("#gFullsizeOverlay*").remove(); + $("#gFullsize").remove(); + }); $(window).resize(function() { - $("#gFullsizeOverlay").width($(document).width()) - .height($(document).height()); - image_size = $.gallery_auto_fit_window(image_width, image_height); - $("#gFullsize").height(image_size.height) - .width(image_size.width) - .css("top", image_size.top) - .css("left", image_size.left); - $("#gFullSizeImage").height(image_size.height) - .width(image_size.width); - }); + $("#gFullsizeOverlay").width($(document).width()).height($(document).height()); + image_size = $.gallery_auto_fit_window(image_width, image_height); + $("#gFullsize").height(image_size.height) + .width(image_size.width) + .css("top", image_size.top) + .css("left", image_size.left); + $("#gFullSizeImage").height(image_size.height).width(image_size.width); + }); }; })(jQuery); -- cgit v1.2.3 From 93138f6ae78fd5ef11ea5095156827592f61bc56 Mon Sep 17 00:00:00 2001 From: Tim Almdal Date: Thu, 27 Aug 2009 15:04:14 -0700 Subject: Don't display the slideshow icon if there are no descendants. ticket #660 --- modules/slideshow/helpers/slideshow_event.php | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/modules/slideshow/helpers/slideshow_event.php b/modules/slideshow/helpers/slideshow_event.php index cf79f71a..1b881de4 100644 --- a/modules/slideshow/helpers/slideshow_event.php +++ b/modules/slideshow/helpers/slideshow_event.php @@ -31,13 +31,17 @@ class slideshow_event_Core { } static function album_menu($menu, $theme) { - $menu - ->append(Menu::factory("link") - ->id("slideshow") - ->label(t("View slideshow")) - ->url("javascript:PicLensLite.start(" . - "{maxScale:0,feedUrl:PicLensLite.indexFeeds()[0].url})") - ->css_id("gSlideshowLink")); + $descendants_count = ORM::factory("item", $theme->item->id) + ->descendants_count(array("type" => "photo")); + if ($descendants_count > 1) { + $menu + ->append(Menu::factory("link") + ->id("slideshow") + ->label(t("View slideshow")) + ->url("javascript:PicLensLite.start(" . + "{maxScale:0,feedUrl:PicLensLite.indexFeeds()[0].url})") + ->css_id("gSlideshowLink")); + } } static function photo_menu($menu, $theme) { -- cgit v1.2.3 From 254feecd0af2da2bfb92ce3995ed65dcbebfd02b Mon Sep 17 00:00:00 2001 From: Tim Almdal Date: Thu, 27 Aug 2009 15:22:27 -0700 Subject: Fix ticket #644 1) remove close button 2) extend the grey overlay to the document size 3) allow any keypress to close the fullize image 4) click on the fullsize will close --- lib/gallery.show_full_size.js | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/lib/gallery.show_full_size.js b/lib/gallery.show_full_size.js index 2f365f0d..1f74e6e2 100644 --- a/lib/gallery.show_full_size.js +++ b/lib/gallery.show_full_size.js @@ -10,7 +10,7 @@ $("body").append('
                      '); @@ -27,10 +27,14 @@ '
                      '); - $("#gFullsize").append(''); - $("#gFullsizeClose").click(function() { + //$("#gFullsize").append(''); + $("#gFullsize").click(function() { + $("#gFullsizeOverlay*").remove(); + $("#gFullsize").remove(); + }); + $().bind("keypress", function() { $("#gFullsizeOverlay*").remove(); $("#gFullsize").remove(); }); -- cgit v1.2.3 From 5235c7a0b79d12305d99fdafe2710583f5368fcc Mon Sep 17 00:00:00 2001 From: Tim Almdal Date: Thu, 27 Aug 2009 15:37:18 -0700 Subject: Allow clicking on the overlay to close the fullsize and remove some debug code --- lib/gallery.show_full_size.js | 35 +++++++++++++++-------------------- 1 file changed, 15 insertions(+), 20 deletions(-) diff --git a/lib/gallery.show_full_size.js b/lib/gallery.show_full_size.js index 1f74e6e2..7e826c32 100644 --- a/lib/gallery.show_full_size.js +++ b/lib/gallery.show_full_size.js @@ -27,27 +27,22 @@ '
                    '); - //$("#gFullsize").append(''); - $("#gFullsize").click(function() { - $("#gFullsizeOverlay*").remove(); - $("#gFullsize").remove(); - }); + $().click(function() { + $("#gFullsizeOverlay*").remove(); + $("#gFullsize").remove(); + }); $().bind("keypress", function() { - $("#gFullsizeOverlay*").remove(); - $("#gFullsize").remove(); - }); + $("#gFullsizeOverlay*").remove(); + $("#gFullsize").remove(); + }); $(window).resize(function() { - $("#gFullsizeOverlay").width($(document).width()) - .height($(document).height()); - image_size = $.gallery_auto_fit_window(image_width, image_height); - $("#gFullsize").height(image_size.height) - .width(image_size.width) - .css("top", image_size.top) - .css("left", image_size.left); - $("#gFullSizeImage").height(image_size.height) - .width(image_size.width); - }); + $("#gFullsizeOverlay").width($(document).width()).height($(document).height()); + image_size = $.gallery_auto_fit_window(image_width, image_height); + $("#gFullsize").height(image_size.height) + .width(image_size.width) + .css("top", image_size.top) + .css("left", image_size.left); + $("#gFullSizeImage").height(image_size.height).width(image_size.width); + }); }; })(jQuery); -- cgit v1.2.3 From a28dd09c4eac11ce406525ffd871df7605d5175f Mon Sep 17 00:00:00 2001 From: Bharat Mediratta Date: Thu, 27 Aug 2009 17:04:48 -0700 Subject: Properly deal with invalid images. This fixes ticket #611 which shows a BMP masquerading as a .jpg causing us to be unable to rebuild resizes and thumbnails. Now if that happens, we discard the file, log it and move on. --- modules/gallery/controllers/simple_uploader.php | 2 +- modules/gallery/helpers/photo.php | 8 +++++-- modules/gallery/views/simple_uploader.html.php | 2 +- modules/server_add/controllers/server_add.php | 30 +++++++++++++++---------- 4 files changed, 26 insertions(+), 16 deletions(-) diff --git a/modules/gallery/controllers/simple_uploader.php b/modules/gallery/controllers/simple_uploader.php index e7c0bd6f..156d18ac 100644 --- a/modules/gallery/controllers/simple_uploader.php +++ b/modules/gallery/controllers/simple_uploader.php @@ -71,7 +71,7 @@ class Simple_Uploader_Controller extends Controller { unlink($temp_filename); } header("HTTP/1.1 500 Internal Server Error"); - print "ERROR:" . $e->getMessage(); + print "ERROR: " . $e->getMessage(); return; } unlink($temp_filename); diff --git a/modules/gallery/helpers/photo.php b/modules/gallery/helpers/photo.php index 5cf37de1..96a66d29 100644 --- a/modules/gallery/helpers/photo.php +++ b/modules/gallery/helpers/photo.php @@ -109,8 +109,12 @@ class photo_Core { // there's only one save() happening here. module::event("item_created", $photo); - // Build our thumbnail/resizes - graphics::generate($photo); + // Build our thumbnail/resizes. If we fail to build thumbnail/resize we assume that the image + // is bad in some way and discard it. + if (!graphics::generate($photo)) { + $photo->delete(); + throw new Exception("@todo BAD_IMAGE_FILE"); + } // If the parent has no cover item, make this it. if (access::can("edit", $parent) && $parent->album_cover_item_id == null) { diff --git a/modules/gallery/views/simple_uploader.html.php b/modules/gallery/views/simple_uploader.html.php index 38ac518c..29a0dfe8 100644 --- a/modules/gallery/views/simple_uploader.html.php +++ b/modules/gallery/views/simple_uploader.html.php @@ -218,7 +218,7 @@ var fp = new File_Progress(file); switch (error_code) { case SWFUpload.UPLOAD_ERROR.HTTP_ERROR: - fp.set_status("error", "" + message); + fp.set_status("error", ""); break; case SWFUpload.UPLOAD_ERROR.UPLOAD_FAILED: fp.set_status("error", ""); diff --git a/modules/server_add/controllers/server_add.php b/modules/server_add/controllers/server_add.php index bfb96506..26b3bd08 100644 --- a/modules/server_add/controllers/server_add.php +++ b/modules/server_add/controllers/server_add.php @@ -220,19 +220,25 @@ class Server_Add_Controller extends Admin_Controller { $album = album::create($parent, $name, $title, null, $owner_id); $entry->item_id = $album->id; } else { - $extension = strtolower(pathinfo($name, PATHINFO_EXTENSION)); - if (in_array($extension, array("gif", "png", "jpg", "jpeg"))) { - $photo = photo::create($parent, $entry->file, $name, $title, null, $owner_id); - $entry->item_id = $photo->id; - } else if (in_array($extension, array("flv", "mp4"))) { - $movie = movie::create($parent, $entry->file, $name, $title, null, $owner_id); - $entry->item_id = $movie->id; - } else { - // This should never happen, because we don't add stuff to the list that we can't - // process. But just in, case.. set this to a non-null value so that we skip this - // entry. + try { + $extension = strtolower(pathinfo($name, PATHINFO_EXTENSION)); + if (in_array($extension, array("gif", "png", "jpg", "jpeg"))) { + $photo = photo::create($parent, $entry->file, $name, $title, null, $owner_id); + $entry->item_id = $photo->id; + } else if (in_array($extension, array("flv", "mp4"))) { + $movie = movie::create($parent, $entry->file, $name, $title, null, $owner_id); + $entry->item_id = $movie->id; + } else { + // This should never happen, because we don't add stuff to the list that we can't + // process. But just in, case.. set this to a non-null value so that we skip this + // entry. + $entry->item_id = 0; + $task->log("Skipping unknown file type: $entry->file"); + } + } catch (Exception $e) { + // This can happen if a photo file is invalid, like a BMP masquerading as a .jpg $entry->item_id = 0; - $task->log("Skipping unknown file type: $entry->file"); + $task->log("Skipping invalid file: $entry->file"); } } -- cgit v1.2.3 From 826e104fa98eca33afd8cb59ebf8123021145609 Mon Sep 17 00:00:00 2001 From: Bharat Mediratta Date: Thu, 27 Aug 2009 17:15:20 -0700 Subject: Get rid of the extra "Folder name" row. It's noisy. Fixes ticket #593. --- modules/info/views/info_block.html.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/info/views/info_block.html.php b/modules/info/views/info_block.html.php index 762e989b..3c668168 100644 --- a/modules/info/views/info_block.html.php +++ b/modules/info/views/info_block.html.php @@ -10,9 +10,9 @@ description)) ?> - id != 1): ?> + is_album()): ?>
                  • - page_type == 'album' ? t("Folder name:"): t("File name:"); ?> + name) ?>
                  • -- cgit v1.2.3 From 3d2e36f5b601b5a274efd0c55bf161448409682a Mon Sep 17 00:00:00 2001 From: jhilden Date: Thu, 27 Aug 2009 20:34:42 -0400 Subject: fixed CSS bug in the simple uploader #629 and improved permissions UI to include breadcrumbs (consistent with the uploader dialog) --- modules/gallery/views/permissions_browse.html.php | 42 +++++++++++------------ themes/default/css/screen.css | 19 ++++++---- 2 files changed, 34 insertions(+), 27 deletions(-) diff --git a/modules/gallery/views/permissions_browse.html.php b/modules/gallery/views/permissions_browse.html.php index 888a27f7..f990896c 100644 --- a/modules/gallery/views/permissions_browse.html.php +++ b/modules/gallery/views/permissions_browse.html.php @@ -5,8 +5,9 @@ $.ajax({ url: form_url.replace("__ITEM__", id), success: function(data) { - $("div.form").slideUp(); - $("div#edit-" + id).html(data).slideDown(); + $("#gEditPermissionForm").html(data); + $(".active").removeClass("active"); + $("#item-" + id).addClass("active"); } }); } @@ -18,7 +19,7 @@ url: action_url.replace("__CMD__", cmd).replace("__GROUP__", group_id). replace("__PERM__", perm_id).replace("__ITEM__", item_id), success: function(data) { - $("div#edit-" + item_id).load(form_url.replace("__ITEM__", item_id)); + $("#gEditPermissionForm").load(form_url.replace("__ITEM__", item_id)); } }); } @@ -31,26 +32,25 @@
                  -
                + +
                + +
                + \ No newline at end of file diff --git a/themes/default/css/screen.css b/themes/default/css/screen.css index 55839c57..ecae2bb2 100644 --- a/themes/default/css/screen.css +++ b/themes/default/css/screen.css @@ -718,7 +718,7 @@ form .gError, font-weight: bold; } -#gAddPhotos .gBreadcrumbs { +#gDialog .gBreadcrumbs li { font-size: .9em; } @@ -901,6 +901,10 @@ form .gError, display: none; } +#gDialog p { + margin: 0; +} + /* jQuery UI ThemeRoller buttons */ .gButtonLink { @@ -1001,6 +1005,14 @@ form .gError, /* Permissions ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ +#gEditPermissionForm { + clear: both; +} +#gEditPermissionForm fieldset { + border: 1px solid #cccccc; + padding: 0; +} + #gPermissions .gDenied, #gPermissions .gAllowed { text-align: center; @@ -1022,11 +1034,6 @@ form .gError, display: inline-block; } -#gAddPhotos p { - margin: 0; - padding: 0; -} - #gAddPhotosCanvas { height: 325px; width: 450px; -- cgit v1.2.3 From 7c5275a63c5e17e519e2ccd497e4d2af97e84503 Mon Sep 17 00:00:00 2001 From: Bharat Mediratta Date: Fri, 28 Aug 2009 09:08:39 -0700 Subject: Fix indentation. --- modules/organize/views/organize_dialog.html.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/organize/views/organize_dialog.html.php b/modules/organize/views/organize_dialog.html.php index cd987819..89182347 100644 --- a/modules/organize/views/organize_dialog.html.php +++ b/modules/organize/views/organize_dialog.html.php @@ -22,7 +22,7 @@
                "> + ref="">
                -- cgit v1.2.3 From e8a3fe97a43dc257a70431defbcc6fb330cdfee2 Mon Sep 17 00:00:00 2001 From: Bharat Mediratta Date: Fri, 28 Aug 2009 09:09:33 -0700 Subject: Fix whitespace. --- modules/organize/views/organize_dialog.html.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/organize/views/organize_dialog.html.php b/modules/organize/views/organize_dialog.html.php index 89182347..3acee05c 100644 --- a/modules/organize/views/organize_dialog.html.php +++ b/modules/organize/views/organize_dialog.html.php @@ -14,7 +14,7 @@
                -
                +
                  -- cgit v1.2.3 From 83e850bc332ce6c13f9b0b7a396f2fe8d9260eb6 Mon Sep 17 00:00:00 2001 From: Bharat Mediratta Date: Fri, 28 Aug 2009 09:19:20 -0700 Subject: Minor style fixes. --- modules/organize/js/organize.js | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/modules/organize/js/organize.js b/modules/organize/js/organize.js index 0f8f7fa1..ec6bd924 100644 --- a/modules/organize/js/organize.js +++ b/modules/organize/js/organize.js @@ -8,16 +8,19 @@ helper: function(event, ui) { var selected = $(".ui-draggable.ui-state-selected img"); if (selected.length) { - var set = $('
                  ').css({zIndex: 2000, width: 80, height: Math.ceil(selected.length / 5) * 16 }), - offset = $(this).offset(), - click = { left: event.pageX - offset.left, top: event.pageY - offset.top }; + var set = $('
                  ') + .css({ + zIndex: 2000, + width: 80, + height: Math.ceil(selected.length / 5) * 16 + }); + var offset = $(this).offset(); + var click = {left: event.pageX - offset.left, top: event.pageY - offset.top}; selected.each(function(i) { var row = parseInt(i / 5); var j = i - (row * 5); - var o = $(this).offset(); - var copy = $(this).clone() .css({ width: $(this).width(), height: $(this).height(), display: "block", @@ -25,7 +28,7 @@ left: o.left - event.pageX, top: o.top - event.pageY }) .appendTo(set) - .animate({width: 10, height: 10, outlineWidth: 1, margin: 1, left: (20 * j), top: (row * 20)}, 500); + .animate({ width: 10, height: 10, outlineWidth: 1, margin: 1, left: (20 * j), top: (row * 20) }, 500); }); return set; } @@ -35,6 +38,7 @@ start: function(event, ui) { $("#gMicroThumbPanel .ui-state-selected").hide(); }, + drag: function(event, ui) { var top = $("#gMicroThumbPanel").offset().top; var height = $("#gMicroThumbPanel").height(); @@ -52,8 +56,9 @@ greedy: true, drop: function(event, ui) { $.organize.do_drop({ - url: rearrange_url.replace("__TARGET_ID__", $(".currentDropTarget").attr("ref")) - .replace("__BEFORE__", $(".currentDropTarget").css("borderLeftStyle") == "solid" ? "before" : "after"), + url: rearrange_url + .replace("__TARGET_ID__", $(".currentDropTarget").attr("ref")) + .replace("__BEFORE__", $(".currentDropTarget").css("borderLeftStyle") == "solid" ? "before" : "after"), source: $(ui.helper).children("img") }); } @@ -86,8 +91,9 @@ if (source_ids.length) { $("#gOrganize .gProgressBar").progressbar().progressbar("value", 0); $("#gOrganizeProgress").animate( - {height: "toggle", display: "toggle"}, - {duration: "fast", + { height: "toggle", display: "toggle" }, + { + duration: "fast", step: function() { }, complete: function() { -- cgit v1.2.3 From 98361e76134fd7ed5df40f2bcde30fd7f5d51708 Mon Sep 17 00:00:00 2001 From: Bharat Mediratta Date: Fri, 28 Aug 2009 09:25:29 -0700 Subject: Add a @todo to defer loading the script/css to the organize dialog. --- modules/organize/helpers/organize_theme.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/modules/organize/helpers/organize_theme.php b/modules/organize/helpers/organize_theme.php index de812261..61b6fe7d 100644 --- a/modules/organize/helpers/organize_theme.php +++ b/modules/organize/helpers/organize_theme.php @@ -21,6 +21,10 @@ class organize_theme { static function head($theme) { $item = $theme->item(); if ($item && access::can("edit", $item) && $item->is_album()) { + // @todo: Defer loading js/css until we're loading the organize dialog as

                  diff --git a/themes/admin_default/css/admin_screen.css b/themes/admin_default/css/admin_screen.css index d408acf0..913631dc 100644 --- a/themes/admin_default/css/admin_screen.css +++ b/themes/admin_default/css/admin_screen.css @@ -451,8 +451,20 @@ li.gDefaultGroup h4, li.gDefaultGroup .gUser { cursor: pointer; } -#gLanguageSettingsForm .checklist li { - width: 150px; - overflow: hidden; +#gLanguagesForm table { + width: 400px; + float: left; + margin: 0 3em 1em 0; +} +#gLanguagesForm .installed { + background-color: #EEEEEE; } +#gLanguagesForm .default { + background-color: #C5DBEC; + font-weight: bold; +} +#gLanguagesForm input, #gShareTranslationsForm, #gLanguages h2 { + clear: both; +} + -- cgit v1.2.3 From 1d5262f9c354a8564f05a8a31b915ad479f4d361 Mon Sep 17 00:00:00 2001 From: Tim Almdal Date: Fri, 28 Aug 2009 13:44:01 -0700 Subject: Fix ticket #591: reCaptcha always on the page. 1) move creating the "Add a comment" button into the comments.html.php 2) use $.get() to retrieve the comment add form --- modules/comment/helpers/comment_theme.php | 2 -- modules/comment/js/comment.js | 10 +++++++++- modules/comment/views/comments.html.php | 10 ++++++++-- themes/default/css/screen.css | 7 +++++++ themes/default/js/ui.init.js | 12 ------------ themes/default/views/movie.html.php | 3 --- themes/default/views/photo.html.php | 3 --- 7 files changed, 24 insertions(+), 23 deletions(-) diff --git a/modules/comment/helpers/comment_theme.php b/modules/comment/helpers/comment_theme.php index b807e2cf..38a00b5c 100644 --- a/modules/comment/helpers/comment_theme.php +++ b/modules/comment/helpers/comment_theme.php @@ -26,7 +26,6 @@ class comment_theme_Core { static function photo_bottom($theme) { $block = new Block; $block->css_id = "gComments"; - $block->anchor = t("comments"); $block->title = t("Comments"); $view = new View("comments.html"); @@ -37,7 +36,6 @@ class comment_theme_Core { ->find_all(); $block->content = $view; - $block->content .= comment::get_add_form($theme->item())->render("form.html"); return $block; } } \ No newline at end of file diff --git a/modules/comment/js/comment.js b/modules/comment/js/comment.js index 00fc6027..9fd63c1a 100644 --- a/modules/comment/js/comment.js +++ b/modules/comment/js/comment.js @@ -1,5 +1,13 @@ $("document").ready(function() { - ajaxify_comment_form(); + $("#gAddCommentButton").click(function(event) { + event.preventDefault(); + $.get($(this).attr("href"), + {}, + function(data) { + $("#gCommentDetail").append(data); + ajaxify_comment_form(); + }); + }); }); function ajaxify_comment_form() { diff --git a/modules/comment/views/comments.html.php b/modules/comment/views/comments.html.php index f7251389..6dce9971 100644 --- a/modules/comment/views/comments.html.php +++ b/modules/comment/views/comments.html.php @@ -1,11 +1,17 @@ + id})") ?>" id="gAddCommentButton" + class="gButtonLink ui-corner-all ui-icon-left ui-state-default right"> + + + +
                  count()): ?>

                  comment!", array("attrs" => "href=\"#add_comment_form\" class=\"showCommentForm\"")) ?>

                  -
                    +
                    • @@ -26,4 +32,4 @@

                    - +
                  diff --git a/themes/default/css/screen.css b/themes/default/css/screen.css index ecae2bb2..481581a2 100644 --- a/themes/default/css/screen.css +++ b/themes/default/css/screen.css @@ -530,6 +530,7 @@ form .gError, #gContent #gComments { margin-top: 2em; + position: relative; } #gContent #gComments ul li { @@ -561,6 +562,12 @@ form .gError, width: 32px; } +#gAddCommentButton { + position: absolute; + right: 0; + top: 2px; +} + #gContent #gAddCommentForm { margin-top: 2em; } diff --git a/themes/default/js/ui.init.js b/themes/default/js/ui.init.js index 2391f638..67cdb968 100644 --- a/themes/default/js/ui.init.js +++ b/themes/default/js/ui.init.js @@ -110,18 +110,6 @@ $(document).ready(function() { $(this).gallery_context_menu(); }); - // Collapse comments form, insert button to expand - if ($("#gAddCommentForm").length) { - var showCommentForm = '' - + '' + ADD_A_COMMENT + ''; - $("#gAddCommentForm").hide(); - $("#gComments").prepend(showCommentForm); - $(".showCommentForm").click(function(){ - $("#gAddCommentForm").show(1000); - }); - } - // Add scroll effect for links to named anchors $.localScroll({ queue: true, diff --git a/themes/default/views/movie.html.php b/themes/default/views/movie.html.php index c8ecd769..29789f8e 100644 --- a/themes/default/views/movie.html.php +++ b/themes/default/views/movie.html.php @@ -32,9 +32,6 @@
                  description)) ?>
                - photo_bottom() ?> context_menu($item, "#gMovieId-{$item->id}") ?>
                diff --git a/themes/default/views/photo.html.php b/themes/default/views/photo.html.php index fa5def47..39e61ef6 100644 --- a/themes/default/views/photo.html.php +++ b/themes/default/views/photo.html.php @@ -55,8 +55,5 @@
                description)) ?>
                - photo_bottom() ?> -- cgit v1.2.3 From c428e49f3273f04fd220107b4992e6177aa1b265 Mon Sep 17 00:00:00 2001 From: Chad Kieffer Date: Fri, 28 Aug 2009 15:24:21 -0600 Subject: Make gMessage 100% of the width of its container. --- themes/admin_default/css/screen.css | 2 +- themes/default/css/screen.css | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/themes/admin_default/css/screen.css b/themes/admin_default/css/screen.css index 88631e81..062c0e41 100644 --- a/themes/admin_default/css/screen.css +++ b/themes/admin_default/css/screen.css @@ -276,7 +276,7 @@ li.gError select { /* Status messages ~~~~~~~~~~~~~~~~~~~~~~~ */ #gMessage { - width: 99%; + width: 100%; } #gAdminAkismet .gSuccess, diff --git a/themes/default/css/screen.css b/themes/default/css/screen.css index 26339e35..8a8f634a 100644 --- a/themes/default/css/screen.css +++ b/themes/default/css/screen.css @@ -276,7 +276,7 @@ li.gError select { /* Status messages ~~~~~~~~~~~~~~~~~~~~~~~ */ #gMessage { - width: 99%; + width: 100%; } #gAdminAkismet .gSuccess, -- cgit v1.2.3 From cb2171d0825251d619b53f6f80d217326fb6bab5 Mon Sep 17 00:00:00 2001 From: Bharat Mediratta Date: Fri, 28 Aug 2009 14:27:37 -0700 Subject: Display the sort order in the Organize dialog, and allow users to change the sort order on the fly. --- modules/gallery/helpers/album.php | 21 ++++++--- modules/organize/controllers/organize.php | 21 ++++++++- modules/organize/css/organize.css | 59 ++++--------------------- modules/organize/js/organize.js | 22 +++++++-- modules/organize/views/organize_dialog.html.php | 20 ++++----- 5 files changed, 71 insertions(+), 72 deletions(-) diff --git a/modules/gallery/helpers/album.php b/modules/gallery/helpers/album.php index 1b6b875d..d46f21ac 100644 --- a/modules/gallery/helpers/album.php +++ b/modules/gallery/helpers/album.php @@ -116,13 +116,7 @@ class album_Core { $sort_order->dropdown("column", array("id" => "gAlbumSortColumn")) ->label(t("Sort by")) - ->options(array("weight" => t("Manual"), - "captured" => t("Date captured"), - "created" => t("Date uploaded"), - "title" => t("Title"), - "updated" => t("Date modified"), - "view_count" => t("Number of views"), - "rand_key" => t("Random"))) + ->options(album::get_sort_order_options()) ->selected($parent->sort_column); $sort_order->dropdown("direction", array("id" => "gAlbumSortDirection")) ->label(t("Order")) @@ -137,4 +131,17 @@ class album_Core { $form->add_rules_from(ORM::factory("item")); return $form; } + + /** + * Return a structured set of all the possible sort orders. + */ + static function get_sort_order_options() { + return array("weight" => t("Manual"), + "captured" => t("Date captured"), + "created" => t("Date uploaded"), + "title" => t("Title"), + "updated" => t("Date modified"), + "view_count" => t("Number of views"), + "rand_key" => t("Random")); + } } diff --git a/modules/organize/controllers/organize.php b/modules/organize/controllers/organize.php index f56ad006..10b109f6 100644 --- a/modules/organize/controllers/organize.php +++ b/modules/organize/controllers/organize.php @@ -25,7 +25,7 @@ class Organize_Controller extends Controller { access::required("edit", $item); $v = new View("organize_dialog.html"); - $v->title = $item->title; + $v->album = $item; $parents = array(); foreach ($item->parents() as $parent) { $parents[$parent->id] = 1; @@ -84,6 +84,25 @@ class Organize_Controller extends Controller { "url" => url::site("organize/run/$task->id?csrf=" . access::csrf_token()))); } + function resort($target_id, $col, $dir) { + access::verify_csrf(); + + $album = ORM::factory("item", $target_id); + access::required("view", $album); + access::required("edit", $album); + + $options = album::get_sort_order_options(); + if (!isset($options[$col])) { + return; + } + + $album->sort_column = $col; + $album->sort_order = $dir; + $album->save(); + + print self::_get_micro_thumb_grid($album, 0); + } + private static function _get_micro_thumb_grid($item, $offset) { $v = new View("organize_thumb_grid.html"); $v->item = $item; diff --git a/modules/organize/css/organize.css b/modules/organize/css/organize.css index d717bcae..52de87fc 100644 --- a/modules/organize/css/organize.css +++ b/modules/organize/css/organize.css @@ -134,63 +134,20 @@ } /**************************************************************** - * Organize Edit Drawer styling + * Organize Controls styling */ -#gOrganizeEditDrawer { +#gOrganizeControls { + padding-left: 8px; background-color: #13A; + color: #ccc; width: 100% !important; } -#gOrganizeEditDrawerPanel { - background-color: #fff; - border: 1px solid #13A; - display: none; - height: 195px; -} - -#gOrganizeEditDrawerHandle { - height: 30px; -} - -#gOrganizeEditHandleLeft { - background-color: #FFF; - float: left; - height: 30px; - width: 15px; -} - -#gOrganizeEditHandleButtonsMiddle, -#gOrganizeEditHandleButtonsLeft { - float: left; - height: 20px; - padding: 2px 10px; -} - -#gOrganizeEditHandleButtonsMiddle { - margin-left: 20px; -} - -#gOrganizeEditHandleButtonsMiddle a, -#gOrganizeEditHandleButtonsLeft a { - float: left; - margin: 0 2.5px; -} - -#gOrganizeEditHandleButtonsRight { - float: right; - height: 20px; - padding: 2px 10px; -} - -#gOrganizeEditHandleButtonsRight a { - float: left; - margin: 0 2.5px; +#gOrganizeControls select { + display: inline; } -#gOrganizeEditHandleRight { - background-color: #FFF; - background-position: -15px 0; +#gOrganizeClose { float: right; - height: 30px; - width: 15px; + margin-right: 12px; } diff --git a/modules/organize/js/organize.js b/modules/organize/js/organize.js index ec6bd924..96309787 100644 --- a/modules/organize/js/organize.js +++ b/modules/organize/js/organize.js @@ -125,9 +125,8 @@ $("#gOrganize .gProgressBar").progressbar("value", data.percent_complete); if (data.done) { var height = $("#gOrganizeProgress").height(); - $("#gOrganizeProgress").toggle(); + $("#gOrganizeProgress").slideUp(); $("#gMicroThumbPanel").height($("#gDialog").innerHeight() - 90); - //$("#gMicroThumbPanel").height($("#gMicroThumbPanel").height() + height); if (data.tree) { $("#gOrganizeAlbumTree").html(data.tree); } @@ -171,10 +170,14 @@ window.location.reload(); }); - $("#gDialog #gMicroThumbDone").click(function(event) { + $("#gDialog #gOrganizeClose").click(function(event) { $("#gDialog").dialog("close"); }); + $("#gOrganizeSortColumn,#gOrganizeSortDir").change(function(event) { + $.organize.resort($("#gOrganizeSortColumn").attr("value"), $("#gOrganizeSortDir").attr("value")); + }); + $.organize.set_handlers(); }, @@ -219,6 +222,19 @@ $("#gMicroThumbGrid").html(data); $.organize.set_handlers(); }); + }, + + /** + * Change the sort order. + */ + resort: function(column, dir) { + var url = sort_order_url + .replace("__COL__", column) + .replace("__DIR__", dir); + $.get(url, function(data) { + $("#gMicroThumbGrid").html(data); + $.organize.set_handlers(); + }); } }; })(jQuery); diff --git a/modules/organize/views/organize_dialog.html.php b/modules/organize/views/organize_dialog.html.php index 7c09266f..a3aae05b 100644 --- a/modules/organize/views/organize_dialog.html.php +++ b/modules/organize/views/organize_dialog.html.php @@ -2,9 +2,10 @@
                -

                p::purify($title))) ?>

                +

                p::purify($album->title))) ?>

                @@ -27,15 +28,14 @@
                -
                -
                -
                -
                -
                - -
                -
                +
                + +
                + + "gOrganizeSortColumn"), album::get_sort_order_options(), $album->sort_column) ?> + "gOrganizeSortDir"), array("ASC" => "Ascending", "DESC" => "Descending"), $album->sort_order) ?> +
                diff --git a/modules/organize/views/organize_thumb_grid.html.php b/modules/organize/views/organize_thumb_grid.html.php index 5adb487a..31dc9af5 100644 --- a/modules/organize/views/organize_thumb_grid.html.php +++ b/modules/organize/views/organize_thumb_grid.html.php @@ -1,5 +1,5 @@ -children(25, $offset) as $child): ?> +children(25, $offset) as $child): ?>
              • "> @@ -8,10 +8,10 @@
              • -children_count() > $offset): ?> +children_count() > $offset): ?> + * + * @return the string escaped for use in JavaScript. + */ + function for_js() { + return self::_escape_for_js($this->_raw_string); + } + + /** + * Safe for use HTML (purified HTML) + * + * Example:
                +   *   
                purified_html() ?> + *
                + * @return the string escaped for use in HTML. + */ + function purified_html() { + if ($this->_is_safe_html) { + return $this; + } else { + return SafeString::of(self::_purify_for_html($this->_raw_string), true); + } + } + + /** + * Returns the raw, unsafe string. Do not use lightly. + */ + function unescaped() { + return $this->_raw_string; + } + + // Escapes special HTML chars ("<", ">", "&", etc.) to HTML entities. + private static function _escape_for_html($dirty_html) { + return html::specialchars($dirty_html); + } + + // Escapes special chars (quotes, backslash, etc.) with a backslash sequence. + private static function _escape_for_js($string) { + // From Smarty plugins/modifier.escape.php + // Might want to be stricter here. + return strtr($string, + array('\\'=>'\\\\',"'"=>"\\'",'"'=>'\\"',"\r"=>'\\r',"\n"=>'\\n',''<\/')); + } + + // Purifies the string, removing any potentially malicious or unsafe HTML / JavaScript. + private static function _purify_for_html($dirty_html) { + if (empty(self::$_purifier)) { + require_once(dirname(__file__) . "/../lib/HTMLPurifier/HTMLPurifier.auto.php"); + $config = HTMLPurifier_Config::createDefault(); + foreach (Kohana::config('purifier') as $category => $key_value) { + foreach ($key_value as $key => $value) { + $config->set("$category.$key", $value); + } + } + self::$_purifier = new HTMLPurifier($config); + } + return self::$_purifier->purify($dirty_html); + } +} diff --git a/modules/gallery/tests/SafeString_Test.php b/modules/gallery/tests/SafeString_Test.php new file mode 100644 index 00000000..cdae3e99 --- /dev/null +++ b/modules/gallery/tests/SafeString_Test.php @@ -0,0 +1,111 @@ +world

                "); + $this->assert_true($safe_string instanceof SafeString); + $this->assert_equal("hello

                world

                ", + $safe_string->unescaped()); + } + + public function toString_escapes_for_html_test() { + $safe_string = new SafeString("hello

                world

                "); + $this->assert_equal("hello <p>world</p>", + $safe_string); + } + + public function toString_for_safe_string_test() { + $safe_string = new SafeString("hello

                world

                "); + $safe_string->mark_html_safe(); + $this->assert_equal("hello

                world

                ", + $safe_string); + } + + public function for_html_test() { + $safe_string = new SafeString("hello

                world

                "); + $this->assert_equal("hello <p>world</p>", + $safe_string->for_html()); + } + + public function safestring_of_safestring_test() { + $safe_string = new SafeString("hello

                world

                "); + $safe_string_2 = new SafeString($safe_string); + $this->assert_true($safe_string_2 instanceof SafeString); + $raw_string = $safe_string_2->unescaped(); + $this->assert_false(is_object($raw_string)); + $this->assert_equal("hello

                world

                ", $raw_string); + $this->assert_equal("hello <p>world</p>", $safe_string_2); + } + + public function for_js_test() { + $safe_string = new SafeString('"Foo\'s bar"'); + $js_string = $safe_string->for_js(); + $this->assert_equal('\\"Foo<\\/em>\\\'s bar\\"', + $js_string); + } + + public function string_safestring_equality_test() { + $safe_string = new SafeString("hello

                world

                "); + $this->assert_equal("hello

                world

                ", + $safe_string->unescaped()); + $escaped_string = "hello <p>world</p>"; + $this->assert_equal($escaped_string, $safe_string); + + $this->assert_true($escaped_string == $safe_string); + $this->assert_false($escaped_string === $safe_string); + $this->assert_false("meow" == $safe_string); + } + + public function of_test() { + $safe_string = SafeString::of("hello

                world

                "); + $this->assert_equal("hello

                world

                ", $safe_string->unescaped()); + } + + public function of_safe_html_test() { + $safe_string = SafeString::of("hello

                world

                ")->mark_html_safe(); + $this->assert_equal("hello

                world

                ", $safe_string->for_html()); + } + + public function of_fluid_api_test() { + $escaped_string = SafeString::of("Foo's bar")->for_js(); + $this->assert_equal("Foo\\'s bar", $escaped_string); + } + + public function safestring_of_safestring_preserves_safe_status_test() { + $safe_string = SafeString::of("hello's

                world

                ")->mark_html_safe(); + $safe_string_2 = new SafeString($safe_string); + $this->assert_equal("hello's

                world

                ", $safe_string_2); + $this->assert_equal("hello\\'s

                world<\\/p>", $safe_string_2->for_js()); + } + + public function safestring_of_safestring_preserves_html_safe_status_test() { + $safe_string = SafeString::of("hello's

                world

                ") + ->mark_html_safe(); + $safe_string_2 = new SafeString($safe_string); + $this->assert_equal("hello's

                world

                ", $safe_string_2); + $this->assert_equal("hello\\'s

                world<\\/p>", $safe_string_2->for_js()); + } + + public function safestring_of_safestring_safe_status_override_test() { + $safe_string = new SafeString("hello

                world

                "); + $safe_string_2 = SafeString::of($safe_string)->mark_html_safe(); + $this->assert_equal("hello

                world

                ", $safe_string_2); + } +} diff --git a/modules/gallery/tests/Xss_Security_Test.php b/modules/gallery/tests/Xss_Security_Test.php index 9bde11dc..1d52237c 100644 --- a/modules/gallery/tests/Xss_Security_Test.php +++ b/modules/gallery/tests/Xss_Security_Test.php @@ -19,87 +19,278 @@ */ class Xss_Security_Test extends Unit_Test_Case { public function find_unescaped_variables_in_views_test() { + $found = array(); foreach (glob("*/*/views/*.php") as $view) { - $expr = null; - $level = 0; - $php = 0; - $str = null; - $in_p_clean = 0; + // List of all tokens without whitespace, simplifying parsing. + $tokens = array(); foreach (token_get_all(file_get_contents($view)) as $token) { - if (false /* useful for debugging */) { - if (is_array($token)) { - printf("[$str] [$in_p_clean] %-15s %s\n", token_name($token[0]), $token[1]); - } else { - printf("[$str] [$in_p_clean] %-15s %s\n", "", $token); - } - } - - // If we find a "(" after a "p::clean" then start counting levels of parens and assume - // that we're inside a p::clean() call until we find the matching close paren. - if ($token[0] == "(" && ($str == "p::clean" || $str == "p::purify")) { - $in_p_clean = 1; - } else if ($token[0] == "(" && $in_p_clean) { - $in_p_clean++; - } else if ($token[0] == ")" && $in_p_clean) { - $in_p_clean--; - } - - // Concatenate runs of strings for convenience, which we use above to figure out if we're - // inside a p::clean() call or not - if ($token[0] == T_STRING || $token[0] == T_DOUBLE_COLON) { - $str .= $token[1]; - } else { - $str = null; - } - - // Scan for any occurrences of < ? = $variable ? > and store it in $expr - if ($token[0] == T_OPEN_TAG_WITH_ECHO) { - $php++; - } else if ($php && $token[0] == T_CLOSE_TAG) { - $php--; - } else if ($php && $token[0] == T_VARIABLE) { - if (!$expr) { - $entry = array($token[2], $in_p_clean); - } - $expr .= $token[1]; - } else if ($expr) { - if ($token[0] == T_OBJECT_OPERATOR) { - $expr .= $token[1]; - } else if ($token[0] == T_STRING) { - $expr .= $token[1]; - } else if ($token == "(") { - $expr .= $token; - $level++; - } else if ($level > 0 && $token == ")") { - $expr .= $token; - $level--; - } else if ($level > 0) { - $expr .= is_array($token) ? $token[1] : $token; - } else { - $entry[] = $expr; - $found[$view][] = $entry; - $expr = null; - $entry = null; - } - } + if (!is_array($token) || ($token[0] != T_WHITESPACE)) { + $tokens[] = $token; + } + } + + $frame = null; + $script_block = 0; + $in_script_block = false; + + for ($token_number = 0; $token_number < count($tokens); $token_number++) { + $token = $tokens[$token_number]; + + // Are we in a block? + if (is_array($token) && $token[0] == T_INLINE_HTML) { + $inline_html = $token[1]; + // T_INLINE_HTML blocks can be split. Need to handle the case + // where one token has "expr_append($inline_html); + } + + // Note: This approach won't catch }i', $inline_html, $matches, PREG_OFFSET_CAPTURE)) { + $last_match = array_pop($matches[0]); + if (is_array($last_match)) { + $closing_script_pos = $last_match[1]; + } else { + $closing_script_pos = $last_match; + } + } + if (preg_match('{]*>}i', $inline_html, $matches, PREG_OFFSET_CAPTURE)) { + $last_match = array_pop($matches[0]); + if (is_array($last_match)) { + $opening_script_pos = $last_match[1]; + } else { + $opening_script_pos = $last_match; + } + } + if ($opening_script_pos != $closing_script_pos) { + $in_script_block = $opening_script_pos > $closing_script_pos; + } + } + + // Look and report each instance of < ? = ... ? > + if (!is_array($token)) { + // A single char token, e.g: ; ( ) + if ($frame) { + $frame->expr_append($token); + } + } else if ($token[0] == T_OPEN_TAG_WITH_ECHO) { + // No need for a stack here - assume < ? = cannot be nested. + $frame = self::_create_frame($token, $in_script_block); + } else if ($frame && $token[0] == T_CLOSE_TAG) { + // Store the < ? = ... ? > block that just ended here. + $found[$view][] = $frame; + $frame = null; + } else if ($frame && $token[0] == T_VARIABLE) { + $frame->expr_append($token[1]); + } else if ($frame && $token[0] == T_STRING) { + $frame->expr_append($token[1]); + // t() and t2() are special in that they're guaranteed to return a SafeString(). + if (in_array($token[1], array("t", "t2"))) { + if (self::_token_matches("(", $tokens, $token_number + 1)) { + $frame->is_safestring(true); + $frame->expr_append("("); + + $token_number++; + $token = $tokens[$token_number]; + } + } else if ($token[1] == "SafeString") { + // Looking for SafeString::of(... + if (self::_token_matches(array(T_DOUBLE_COLON, "::"), $tokens, $token_number + 1) && + self::_token_matches(array(T_STRING, "of"), $tokens, $token_number + 2) && + self::_token_matches("(", $tokens, $token_number + 3)) { + $frame->is_safestring(true); + $frame->expr_append("::of("); + + $token_number += 3; + $token = $tokens[$token_number]; + } + } else if ($token[1] == "json_encode") { + if (self::_token_matches("(", $tokens, $token_number + 1)) { + $frame->json_encode_called(true); + $frame->expr_append("("); + + $token_number++; + $token = $tokens[$token_number]; + } + } + } else if ($frame && $token[0] == T_OBJECT_OPERATOR) { + $frame->expr_append($token[1]); + + if (self::_token_matches(array(T_STRING), $tokens, $token_number + 1) && + in_array($tokens[$token_number + 1][1], + array("for_js", "for_html", "purified_html")) && + self::_token_matches("(", $tokens, $token_number + 2)) { + + $method = $tokens[$token_number + 1][1]; + $frame->expr_append("$method("); + + $token_number += 2; + $token = $tokens[$token_number]; + + if ("for_js" == $method) { + $frame->for_js_called(true); + } else if ("for_html" == $method) { + $frame->for_html_called(true); + } else if ("purified_html" == $method) { + $frame->purified_html_called(true); + } + } + } else if ($frame) { + $frame->expr_append($token[1]); + } } } - $canonical = MODPATH . "gallery/tests/xss_data.txt"; + // Generate the report. + /* + * States for uses of < ? = X ? >: + * JS_XSS: + * In + * + * @return the string escaped for use in HTML attributes. + */ + function for_html_attr() { + $string = (string) $this->for_html(); + return strtr($string, + array("'"=>"'", + '"'=>'"')); + } + /** * Safe for use HTML (purified HTML) * diff --git a/modules/gallery/tests/SafeString_Test.php b/modules/gallery/tests/SafeString_Test.php index cdae3e99..73d82c34 100644 --- a/modules/gallery/tests/SafeString_Test.php +++ b/modules/gallery/tests/SafeString_Test.php @@ -18,13 +18,6 @@ * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ class SafeString_Test extends Unit_Test_Case { - public function p_clean_returns_safestring_instance_test() { - $safe_string = p::clean("hello

                world

                "); - $this->assert_true($safe_string instanceof SafeString); - $this->assert_equal("hello

                world

                ", - $safe_string->unescaped()); - } - public function toString_escapes_for_html_test() { $safe_string = new SafeString("hello

                world

                "); $this->assert_equal("hello <p>world</p>", @@ -61,6 +54,20 @@ class SafeString_Test extends Unit_Test_Case { $js_string); } + public function for_html_attr_test() { + $safe_string = new SafeString('"Foo\'s bar"'); + $attr_string = $safe_string->for_html_attr(); + $this->assert_equal('"<em>Foo</em>'s bar"', + $attr_string); + } + + public function for_html_attr_with_safe_html_test() { + $safe_string = SafeString::of('"Foo\'s bar"')->mark_html_safe(); + $attr_string = $safe_string->for_html_attr(); + $this->assert_equal('"Foo's bar"', + $attr_string); + } + public function string_safestring_equality_test() { $safe_string = new SafeString("hello

                world

                "); $this->assert_equal("hello

                world

                ", -- cgit v1.2.3 From 0d16cc1c106dc324fde59cac54fa82e4a70e04e2 Mon Sep 17 00:00:00 2001 From: Bharat Mediratta Date: Sat, 29 Aug 2009 12:12:53 -0700 Subject: Clean up the test and get it working. --- modules/gallery/tests/Item_Helper_Test.php | 69 ++++++++---------------------- 1 file changed, 17 insertions(+), 52 deletions(-) diff --git a/modules/gallery/tests/Item_Helper_Test.php b/modules/gallery/tests/Item_Helper_Test.php index 48fdd962..3f80733f 100644 --- a/modules/gallery/tests/Item_Helper_Test.php +++ b/modules/gallery/tests/Item_Helper_Test.php @@ -18,65 +18,30 @@ * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ class Item_Helper_Test extends Unit_Test_Case { - private $_group; - private $_album; - private $_item; - //private $_user; - public function teardown() { - try { - $this->_group->delete(); - } catch (Exception $e) { } - - try { - $this->_album->delete(); - } catch (Exception $e) { } - - //try { - // $this->_user->delete(); - //} catch (Exception $e) { } - } - - public function setup() { - } - - public function viewable_item_test() { - $this->_group = group::create("access_test"); + public function viewable_test() { $root = ORM::factory("item", 1); - $this->_album = album::create($root, rand(), "visible_test"); - $this->_user = user::create("visible_test", "Visible Test", ""); - $this->_user->add($this->_group); - $this->_item = self::_create_random_item($this->_album); - comment::create($this->_item, $this->_user, "This is a comment"); - access::deny(group::everybody(), "view", $this->_album); - $active = user::active(); - - $items = ORM::factory("item") - ->where("id", $this->_album->id) - ->find_all(); - print Database::instance()->last_query() . "\n"; - $items = ORM::factory("item") - ->where("id", $this->_album->id) - ->viewable() - ->find_all(); - print Database::instance()->last_query() . "\n"; + $album = album::create($root, rand(), rand(), rand()); + $item = self::_create_random_item($album); + user::set_active(user::guest()); + + // We can see the item when permissions are granted + access::allow(group::everybody(), "view", $album); + $this->assert_equal( + 1, + ORM::factory("item")->viewable()->where("id", $item->id)->count_all()); + + // We can't see the item when permissions are denied + access::deny(group::everybody(), "view", $album); + $this->assert_equal( + 0, + ORM::factory("item")->viewable()->where("id", $item->id)->count_all()); } - //public function viewable_one_restrictions_test() { - // $item = self::create_random_item(); - // $this->assert_true(!empty($item->created)); - // $this->assert_true(!empty($item->updated)); - //} - //public function viewable_multiple_restrictions_test() { - // $item = self::create_random_item(); - // $this->assert_true(!empty($item->created)); - // $this->assert_true(!empty($item->updated)); - //} - private static function _create_random_item($album) { + // Set all required fields (values are irrelevant) $item = ORM::factory("item"); - /* Set all required fields (values are irrelevant) */ $item->name = rand(); $item->type = "photo"; return $item->add_to_parent($album); -- cgit v1.2.3 From 50c624ed1b5a09d965d4e0f18a32bf3c2a94db15 Mon Sep 17 00:00:00 2001 From: Bharat Mediratta Date: Sat, 29 Aug 2009 12:20:03 -0700 Subject: Fix active() to not use user::guest() as the fallback for our Session::get() call. --- modules/user/helpers/user.php | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/modules/user/helpers/user.php b/modules/user/helpers/user.php index 69a6ecb3..40acc2ec 100644 --- a/modules/user/helpers/user.php +++ b/modules/user/helpers/user.php @@ -159,7 +159,12 @@ class user_Core { */ static function active() { // @todo (maybe) cache this object so we're not always doing session lookups. - $user = Session::instance()->get("user", self::guest()); + $user = Session::instance()->get("user", null); + if (!isset($user)) { + // Don't do this as a fallback in the Session::get() call because it can trigger unnecessary + // work. + $user = user::guest(); + } return $user; } -- cgit v1.2.3 From cd1fd4989f394f6e8084b8101a8dbdb3030c52aa Mon Sep 17 00:00:00 2001 From: Bharat Mediratta Date: Sat, 29 Aug 2009 12:22:00 -0700 Subject: Add a test for Comment_Model::viewable(). --- modules/comment/tests/Comment_Model_Test.php | 40 ++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 modules/comment/tests/Comment_Model_Test.php diff --git a/modules/comment/tests/Comment_Model_Test.php b/modules/comment/tests/Comment_Model_Test.php new file mode 100644 index 00000000..f4c68b15 --- /dev/null +++ b/modules/comment/tests/Comment_Model_Test.php @@ -0,0 +1,40 @@ +assert_equal( + 1, + ORM::factory("comment")->viewable()->where("comments.id", $comment->id)->count_all()); + + // We can't see the comment when permissions are denied on the album + access::deny(group::everybody(), "view", $album); + $this->assert_equal( + 0, + ORM::factory("comment")->viewable()->where("comments.id", $comment->id)->count_all()); + } +} -- cgit v1.2.3 From a10063ff68cf5988297dcad889384ab2080c3850 Mon Sep 17 00:00:00 2001 From: Andy Staudacher Date: Sat, 29 Aug 2009 12:34:09 -0700 Subject: Add more factory methods for convenience: SafeString::purify() and SafeString::of_safe_html(). Removing SafeString::mark_html_safe() since it's no longer needed. --- modules/gallery/helpers/MY_url.php | 10 +++++----- modules/gallery/libraries/I18n.php | 2 +- modules/gallery/libraries/SafeString.php | 27 +++++++++++++++++++++------ modules/gallery/tests/SafeString_Test.php | 19 +++++++++++-------- modules/gallery/tests/Xss_Security_Test.php | 7 +++++-- 5 files changed, 43 insertions(+), 22 deletions(-) diff --git a/modules/gallery/helpers/MY_url.php b/modules/gallery/helpers/MY_url.php index b4b7f352..6092a9d8 100644 --- a/modules/gallery/helpers/MY_url.php +++ b/modules/gallery/helpers/MY_url.php @@ -31,7 +31,7 @@ class url extends url_Core { $uri = model_cache::get("item", $parts[1])->relative_path(); } $url = parent::site($uri . $query, $protocol); - return SafeString::of($url)->mark_html_safe(); + return SafeString::of_safe_html($url); } static function parse_url() { @@ -103,22 +103,22 @@ class url extends url_Core { public static function base($index=false, $protocol=false) { $url = parent::base($index, $protocol); - return SafeString::of($url)->mark_html_safe(); + return SafeString::of_safe_html($url); } public static function current($qs=false) { $url = parent::current($qs); - return SafeString::of($url)->mark_html_safe(); + return SafeString::of_safe_html($url); } public static function file($file, $index=false) { $url = parent::file($file, $index); - return SafeString::of($url)->mark_html_safe(); + return SafeString::of_safe_html($url); } public static function merge(array $arguments) { $url = parent::merge($arguments); - return SafeString::of($url)->mark_html_safe(); + return SafeString::of_safe_html($url); } } diff --git a/modules/gallery/libraries/I18n.php b/modules/gallery/libraries/I18n.php index 8dc42e04..a53d5ae9 100644 --- a/modules/gallery/libraries/I18n.php +++ b/modules/gallery/libraries/I18n.php @@ -116,7 +116,7 @@ class I18n_Core { $entry = $this->interpolate($locale, $entry, $values); - return SafeString::of($entry)->mark_html_safe(); + return SafeString::of_safe_html($entry); } private function lookup($locale, $message) { diff --git a/modules/gallery/libraries/SafeString.php b/modules/gallery/libraries/SafeString.php index 709ab5f6..9a269ed4 100644 --- a/modules/gallery/libraries/SafeString.php +++ b/modules/gallery/libraries/SafeString.php @@ -24,6 +24,7 @@ class SafeString_Core { private $_raw_string; protected $_is_safe_html = false; + protected $_is_purified_html = false; private static $_purifier = null; @@ -44,11 +45,25 @@ class SafeString_Core { } /** - * Marks this string as safe to be used in HTML without any escaping. + * Factory method returning a new SafeString instance after HTML purifying + * the given string. */ - function mark_html_safe() { - $this->_is_safe_html = true; - return $this; + static function purify($string) { + if ($string instanceof SafeString) { + $string = $string->unescaped(); + } + $safe_string = self::of_safe_html(self::_purify_for_html($string)); + $safe_string->_is_purified_html = true; + return $safe_string; + } + + /** + * Factory method returning a new SafeString instance which won't HTML escape. + */ + static function of_safe_html($string) { + $safe_string = new SafeString($string); + $safe_string->_is_safe_html = true; + return $safe_string; } /** @@ -117,10 +132,10 @@ class SafeString_Core { * @return the string escaped for use in HTML. */ function purified_html() { - if ($this->_is_safe_html) { + if ($this->_is_purified_html) { return $this; } else { - return SafeString::of(self::_purify_for_html($this->_raw_string), true); + return self::purify($this); } } diff --git a/modules/gallery/tests/SafeString_Test.php b/modules/gallery/tests/SafeString_Test.php index 73d82c34..0fc7f6f3 100644 --- a/modules/gallery/tests/SafeString_Test.php +++ b/modules/gallery/tests/SafeString_Test.php @@ -25,8 +25,7 @@ class SafeString_Test extends Unit_Test_Case { } public function toString_for_safe_string_test() { - $safe_string = new SafeString("hello

                world

                "); - $safe_string->mark_html_safe(); + $safe_string = SafeString::of_safe_html("hello

                world

                "); $this->assert_equal("hello

                world

                ", $safe_string); } @@ -62,7 +61,7 @@ class SafeString_Test extends Unit_Test_Case { } public function for_html_attr_with_safe_html_test() { - $safe_string = SafeString::of('"Foo\'s bar"')->mark_html_safe(); + $safe_string = SafeString::of_safe_html('"Foo\'s bar"'); $attr_string = $safe_string->for_html_attr(); $this->assert_equal('"Foo's bar"', $attr_string); @@ -86,25 +85,29 @@ class SafeString_Test extends Unit_Test_Case { } public function of_safe_html_test() { - $safe_string = SafeString::of("hello

                world

                ")->mark_html_safe(); + $safe_string = SafeString::of_safe_html("hello

                world

                "); $this->assert_equal("hello

                world

                ", $safe_string->for_html()); } + public function purify_test() { + $safe_string = SafeString::purify("hello

                world

                "); + $this->assert_equal("hello

                world

                ", $safe_string); + } + public function of_fluid_api_test() { $escaped_string = SafeString::of("Foo's bar")->for_js(); $this->assert_equal("Foo\\'s bar", $escaped_string); } public function safestring_of_safestring_preserves_safe_status_test() { - $safe_string = SafeString::of("hello's

                world

                ")->mark_html_safe(); + $safe_string = SafeString::of_safe_html("hello's

                world

                "); $safe_string_2 = new SafeString($safe_string); $this->assert_equal("hello's

                world

                ", $safe_string_2); $this->assert_equal("hello\\'s

                world<\\/p>", $safe_string_2->for_js()); } public function safestring_of_safestring_preserves_html_safe_status_test() { - $safe_string = SafeString::of("hello's

                world

                ") - ->mark_html_safe(); + $safe_string = SafeString::of_safe_html("hello's

                world

                "); $safe_string_2 = new SafeString($safe_string); $this->assert_equal("hello's

                world

                ", $safe_string_2); $this->assert_equal("hello\\'s

                world<\\/p>", $safe_string_2->for_js()); @@ -112,7 +115,7 @@ class SafeString_Test extends Unit_Test_Case { public function safestring_of_safestring_safe_status_override_test() { $safe_string = new SafeString("hello

                world

                "); - $safe_string_2 = SafeString::of($safe_string)->mark_html_safe(); + $safe_string_2 = SafeString::of_safe_html($safe_string); $this->assert_equal("hello

                world

                ", $safe_string_2); } } diff --git a/modules/gallery/tests/Xss_Security_Test.php b/modules/gallery/tests/Xss_Security_Test.php index e0e5bb86..fd596c69 100644 --- a/modules/gallery/tests/Xss_Security_Test.php +++ b/modules/gallery/tests/Xss_Security_Test.php @@ -110,10 +110,13 @@ class Xss_Security_Test extends Unit_Test_Case { } else if ($token[1] == "SafeString") { // Looking for SafeString::of(... if (self::_token_matches(array(T_DOUBLE_COLON, "::"), $tokens, $token_number + 1) && - self::_token_matches(array(T_STRING, "of"), $tokens, $token_number + 2) && + self::_token_matches(array(T_STRING), $tokens, $token_number + 2) && + in_array($tokens[$token_number + 2][1], array("of", "of_safe_html", "purify")) && self::_token_matches("(", $tokens, $token_number + 3)) { $frame->is_safestring(true); - $frame->expr_append("::of("); + + $method = $tokens[$token_number + 2][1]; + $frame->expr_append("::$method("); $token_number += 3; $token = $tokens[$token_number]; -- cgit v1.2.3 From c01ac42c4604b3b129e8089e0dc683ebd418b380 Mon Sep 17 00:00:00 2001 From: Andy Staudacher Date: Sat, 29 Aug 2009 12:48:40 -0700 Subject: Refactor all calls of p::clean() to SafeString::of() and p::purify() to SafeString::purify(). Removing any p::clean() calls for arguments to t() and t2() since their args are wrapped in a SafeString anyway. --- modules/comment/controllers/comments.php | 8 +++--- modules/comment/helpers/comment_rss.php | 8 +++--- .../views/admin_block_recent_comments.html.php | 6 ++--- modules/comment/views/admin_comments.html.php | 10 ++++---- modules/comment/views/comment.html.php | 6 ++--- modules/comment/views/comment.mrss.php | 12 ++++----- modules/comment/views/comments.html.php | 6 ++--- modules/digibug/controllers/digibug.php | 2 +- modules/exif/views/exif_dialog.html.php | 4 +-- modules/g2_import/helpers/g2_import.php | 2 +- .../controllers/admin_advanced_settings.php | 2 +- modules/gallery/controllers/movies.php | 2 +- modules/gallery/controllers/photos.php | 2 +- modules/gallery/controllers/quick.php | 10 ++++---- modules/gallery/helpers/gallery_rss.php | 4 +-- modules/gallery/helpers/gallery_task.php | 4 +-- modules/gallery/helpers/p.php | 29 ---------------------- .../gallery/views/admin_advanced_settings.html.php | 8 +++--- .../gallery/views/admin_block_log_entries.html.php | 2 +- .../views/admin_block_photo_stream.html.php | 4 +-- modules/gallery/views/admin_maintenance.html.php | 2 +- .../views/admin_maintenance_show_log.html.php | 2 +- modules/gallery/views/after_install.html.php | 2 +- modules/gallery/views/move_tree.html.php | 8 +++--- modules/gallery/views/permissions_browse.html.php | 4 +-- modules/gallery/views/permissions_form.html.php | 2 +- modules/gallery/views/simple_uploader.html.php | 6 ++--- modules/info/views/info_block.html.php | 10 ++++---- .../notification/views/comment_published.html.php | 12 ++++----- modules/notification/views/item_added.html.php | 8 +++--- modules/notification/views/item_deleted.html.php | 6 ++--- modules/notification/views/item_updated.html.php | 12 ++++----- modules/organize/controllers/organize.php | 10 ++++---- modules/organize/views/organize.html.php | 2 +- modules/organize/views/organize_album.html.php | 2 +- modules/rss/views/feed.mrss.php | 14 +++++------ modules/search/views/search.html.php | 10 ++++---- .../server_add/controllers/admin_server_add.php | 4 +-- modules/server_add/views/server_add_tree.html.php | 2 +- .../views/server_add_tree_dialog.html.php | 6 ++--- modules/tag/controllers/admin_tags.php | 8 +++--- modules/tag/helpers/tag_rss.php | 2 +- modules/tag/views/admin_tags.html.php | 2 +- modules/tag/views/tag_cloud.html.php | 2 +- modules/user/controllers/admin_users.php | 14 +++++------ modules/user/controllers/login.php | 4 +-- modules/user/controllers/logout.php | 4 +-- modules/user/controllers/password.php | 2 +- modules/user/views/admin_users.html.php | 8 +++--- modules/user/views/admin_users_group.html.php | 8 +++--- modules/user/views/login.html.php | 6 ++--- modules/user/views/reset_password.html.php | 2 +- system/helpers/request.php | 2 +- themes/default/views/album.html.php | 4 +-- themes/default/views/dynamic.html.php | 4 +-- themes/default/views/header.html.php | 4 +-- themes/default/views/movie.html.php | 4 +-- themes/default/views/page.html.php | 8 +++--- themes/default/views/photo.html.php | 4 +-- 59 files changed, 159 insertions(+), 188 deletions(-) delete mode 100644 modules/gallery/helpers/p.php diff --git a/modules/comment/controllers/comments.php b/modules/comment/controllers/comments.php index 9fb4796e..87633f4c 100644 --- a/modules/comment/controllers/comments.php +++ b/modules/comment/controllers/comments.php @@ -39,9 +39,9 @@ class Comments_Controller extends REST_Controller { foreach ($comments as $comment) { $data[] = array( "id" => $comment->id, - "author_name" => p::clean($comment->author_name()), + "author_name" => SafeString::of($comment->author_name()), "created" => $comment->created, - "text" => nl2br(p::purify($comment->text))); + "text" => nl2br(SafeString::purify($comment->text))); } print json_encode($data); break; @@ -126,9 +126,9 @@ class Comments_Controller extends REST_Controller { array("result" => "success", "data" => array( "id" => $comment->id, - "author_name" => p::clean($comment->author_name()), + "author_name" => SafeString::of($comment->author_name()), "created" => $comment->created, - "text" => nl2br(p::purify($comment->text))))); + "text" => nl2br(SafeString::purify($comment->text))))); } else { $view = new Theme_View("comment.html", "fragment"); $view->comment = $comment; diff --git a/modules/comment/helpers/comment_rss.php b/modules/comment/helpers/comment_rss.php index ab3d2283..d0f15010 100644 --- a/modules/comment/helpers/comment_rss.php +++ b/modules/comment/helpers/comment_rss.php @@ -23,7 +23,7 @@ class comment_rss_Core { $feeds["comment/newest"] = t("All new comments"); if ($item) { $feeds["comment/item/$item->id"] = - t("Comments on %title", array("title" => p::purify($item->title))); + t("Comments on %title", array("title" => SafeString::purify($item->title))); } return $feeds; } @@ -53,13 +53,13 @@ class comment_rss_Core { $item = $comment->item(); $feed->children[] = new ArrayObject( array("pub_date" => date("D, d M Y H:i:s T", $comment->created), - "text" => nl2br(p::purify($comment->text)), + "text" => nl2br(SafeString::purify($comment->text)), "thumb_url" => $item->thumb_url(), "thumb_height" => $item->thumb_height, "thumb_width" => $item->thumb_width, "item_uri" => url::abs_site("{$item->type}s/$item->id"), - "title" => p::purify($item->title), - "author" => p::clean($comment->author_name())), + "title" => SafeString::purify($item->title), + "author" => SafeString::of($comment->author_name())), ArrayObject::ARRAY_AS_PROPS); } diff --git a/modules/comment/views/admin_block_recent_comments.html.php b/modules/comment/views/admin_block_recent_comments.html.php index 516a8181..2c7a5cf1 100644 --- a/modules/comment/views/admin_block_recent_comments.html.php +++ b/modules/comment/views/admin_block_recent_comments.html.php @@ -4,13 +4,13 @@
              • "> " class="gAvatar" - alt="author_name()) ?>" + alt="author_name()) ?>" width="32" height="32" /> created) ?> %author_name said %comment_text', - array("author_name" => p::clean($comment->author_name()), - "comment_text" => text::limit_words(nl2br(p::purify($comment->text)), 50))); ?> + array("author_name" => SafeString::of($comment->author_name()), + "comment_text" => text::limit_words(nl2br(SafeString::purify($comment->text)), 50))); ?>
              • diff --git a/modules/comment/views/admin_comments.html.php b/modules/comment/views/admin_comments.html.php index 9fe7164b..b27e3166 100644 --- a/modules/comment/views/admin_comments.html.php +++ b/modules/comment/views/admin_comments.html.php @@ -108,12 +108,12 @@ " class="gAvatar" - alt="author_name()) ?>" + alt="author_name()) ?>" width="40" height="40" /> -

                author_name()) ?>

                +

                author_name()) ?>

                created) ?>

                - text)) ?> + text)) ?>
                  diff --git a/modules/comment/views/comment.html.php b/modules/comment/views/comment.html.php index 3d17411c..31bb7f4d 100644 --- a/modules/comment/views/comment.html.php +++ b/modules/comment/views/comment.html.php @@ -4,15 +4,15 @@ " class="gAvatar" - alt="author_name()) ?>" + alt="author_name()) ?>" width="40" height="40" /> gallery::date_time($comment->created), - "author_name" => p::clean($comment->author_name()))) ?> + "author_name" => SafeString::of($comment->author_name()))) ?>

                  - text)) ?> + text)) ?>
                  diff --git a/modules/comment/views/comment.mrss.php b/modules/comment/views/comment.mrss.php index 2b5b13c1..ae7762d9 100644 --- a/modules/comment/views/comment.mrss.php +++ b/modules/comment/views/comment.mrss.php @@ -6,9 +6,9 @@ xmlns:fh="http://purl.org/syndication/history/1.0"> Gallery 3 - <?= p::clean($feed->title) ?> + <?= SafeString::of($feed->title) ?> uri ?> - description) ?> + description) ?> en-us @@ -22,14 +22,14 @@ children as $child): ?> - <?= p::purify($child->title) ?> - item_uri) ?> - author) ?> + <?= SafeString::purify($child->title) ?> + item_uri) ?> + author) ?> item_uri ?> pub_date ?> text)) ?>

                  +

                  text)) ?>

                  diff --git a/modules/comment/views/comments.html.php b/modules/comment/views/comments.html.php index f7251389..7941b7da 100644 --- a/modules/comment/views/comments.html.php +++ b/modules/comment/views/comments.html.php @@ -12,16 +12,16 @@ " class="gAvatar" - alt="author_name()) ?>" + alt="author_name()) ?>" width="40" height="40" /> %name said', array("date" => date("Y-M-d H:i:s", $comment->created), - "name" => p::clean($comment->author_name()))); ?> + "name" => SafeString::of($comment->author_name()))); ?>

                  - text)) ?> + text)) ?>
                  diff --git a/modules/digibug/controllers/digibug.php b/modules/digibug/controllers/digibug.php index e0f4b6bf..509a8b70 100644 --- a/modules/digibug/controllers/digibug.php +++ b/modules/digibug/controllers/digibug.php @@ -50,7 +50,7 @@ class Digibug_Controller extends Controller { "image_width_1" => $item->width, "thumb_height_1" => $item->thumb_height, "thumb_width_1" => $item->thumb_width, - "title_1" => p::purify($item->title)); + "title_1" => SafeString::purify($item->title)); print $v; } diff --git a/modules/exif/views/exif_dialog.html.php b/modules/exif/views/exif_dialog.html.php index 6494b2b0..a981ca09 100644 --- a/modules/exif/views/exif_dialog.html.php +++ b/modules/exif/views/exif_dialog.html.php @@ -14,14 +14,14 @@ - + - + diff --git a/modules/g2_import/helpers/g2_import.php b/modules/g2_import/helpers/g2_import.php index 436cef52..a01ca1db 100644 --- a/modules/g2_import/helpers/g2_import.php +++ b/modules/g2_import/helpers/g2_import.php @@ -590,7 +590,7 @@ class g2_import_Core { self::map($g2_comment->getId(), $comment->id); return t("Imported comment '%comment' for item with id: %id", array("id" => $comment->item_id, - "comment" => text::limit_words(nl2br(p::purify($comment->text)), 50))); + "comment" => text::limit_words(nl2br(SafeString::purify($comment->text)), 50))); } /** diff --git a/modules/gallery/controllers/admin_advanced_settings.php b/modules/gallery/controllers/admin_advanced_settings.php index 64007fdb..d727b654 100644 --- a/modules/gallery/controllers/admin_advanced_settings.php +++ b/modules/gallery/controllers/admin_advanced_settings.php @@ -46,7 +46,7 @@ class Admin_Advanced_Settings_Controller extends Admin_Controller { module::set_var($module_name, $var_name, Input::instance()->post("value")); message::success( t("Saved value for %var (%module_name)", - array("var" => p::clean($var_name), "module_name" => $module_name))); + array("var" => SafeString::of($var_name), "module_name" => $module_name))); print json_encode(array("result" => "success")); } diff --git a/modules/gallery/controllers/movies.php b/modules/gallery/controllers/movies.php index c8227d74..09b16759 100644 --- a/modules/gallery/controllers/movies.php +++ b/modules/gallery/controllers/movies.php @@ -93,7 +93,7 @@ class Movies_Controller extends Items_Controller { log::success("content", "Updated photo", "id\">view"); message::success( - t("Saved photo %photo_title", array("photo_title" => p::clean($photo->title)))); + t("Saved photo %photo_title", array("photo_title" => $photo->title))); print json_encode( array("result" => "success", diff --git a/modules/gallery/controllers/photos.php b/modules/gallery/controllers/photos.php index 8ee24da8..3447b4c6 100644 --- a/modules/gallery/controllers/photos.php +++ b/modules/gallery/controllers/photos.php @@ -86,7 +86,7 @@ class Photos_Controller extends Items_Controller { log::success("content", "Updated photo", "id\">view"); message::success( - t("Saved photo %photo_title", array("photo_title" => p::clean($photo->title)))); + t("Saved photo %photo_title", array("photo_title" => $photo->title))); print json_encode( array("result" => "success", diff --git a/modules/gallery/controllers/quick.php b/modules/gallery/controllers/quick.php index de027c1b..98a5bf9f 100644 --- a/modules/gallery/controllers/quick.php +++ b/modules/gallery/controllers/quick.php @@ -89,7 +89,7 @@ class Quick_Controller extends Controller { access::required("view", $item->parent()); access::required("edit", $item->parent()); - $msg = t("Made %title this album's cover", array("title" => p::purify($item->title))); + $msg = t("Made %title this album's cover", array("title" => SafeString::purify($item->title))); item::make_album_cover($item); message::success($msg); @@ -105,10 +105,10 @@ class Quick_Controller extends Controller { if ($item->is_album()) { print t( "Delete the album %title? All photos and movies in the album will also be deleted.", - array("title" => p::purify($item->title))); + array("title" => SafeString::purify($item->title))); } else { print t("Are you sure you want to delete %title?", - array("title" => p::purify($item->title))); + array("title" => SafeString::purify($item->title))); } $form = item::get_delete_form($item); @@ -122,9 +122,9 @@ class Quick_Controller extends Controller { access::required("edit", $item); if ($item->is_album()) { - $msg = t("Deleted album %title", array("title" => p::purify($item->title))); + $msg = t("Deleted album %title", array("title" => SafeString::purify($item->title))); } else { - $msg = t("Deleted photo %title", array("title" => p::purify($item->title))); + $msg = t("Deleted photo %title", array("title" => SafeString::purify($item->title))); } $parent = $item->parent(); diff --git a/modules/gallery/helpers/gallery_rss.php b/modules/gallery/helpers/gallery_rss.php index 7daf6170..be555296 100644 --- a/modules/gallery/helpers/gallery_rss.php +++ b/modules/gallery/helpers/gallery_rss.php @@ -52,9 +52,9 @@ class gallery_rss_Core { ->viewable() ->descendants($limit, $offset, "photo"); $feed->max_pages = ceil($item->viewable()->descendants_count("photo") / $limit); - $feed->title = p::purify($item->title); + $feed->title = SafeString::purify($item->title); $feed->link = url::abs_site("albums/{$item->id}"); - $feed->description = nl2br(p::purify($item->description)); + $feed->description = nl2br(SafeString::purify($item->description)); return $feed; } diff --git a/modules/gallery/helpers/gallery_task.php b/modules/gallery/helpers/gallery_task.php index 9edc3acd..8c0e8aa8 100644 --- a/modules/gallery/helpers/gallery_task.php +++ b/modules/gallery/helpers/gallery_task.php @@ -64,10 +64,10 @@ class gallery_task_Core { if (!$success) { $ignored[$item->id] = 1; $errors[] = t("Unable to rebuild images for '%title'", - array("title" => p::purify($item->title))); + array("title" => SafeString::purify($item->title))); } else { $errors[] = t("Successfully rebuilt images for '%title'", - array("title" => p::purify($item->title))); + array("title" => SafeString::purify($item->title))); } } diff --git a/modules/gallery/helpers/p.php b/modules/gallery/helpers/p.php deleted file mode 100644 index e852c086..00000000 --- a/modules/gallery/helpers/p.php +++ /dev/null @@ -1,29 +0,0 @@ -purified_html(); - } -} diff --git a/modules/gallery/views/admin_advanced_settings.html.php b/modules/gallery/views/admin_advanced_settings.html.php index b37c1c73..adc15b91 100644 --- a/modules/gallery/views/admin_advanced_settings.html.php +++ b/modules/gallery/views/admin_advanced_settings.html.php @@ -20,13 +20,13 @@ module_name == "gallery" && $var->name == "_cache") continue ?> module_name ?> - name) ?> + name) ?> - module_name/" . p::clean($var->name)) ?>" + module_name/" . SafeString::of($var->name)) ?>" class="gDialogLink" - title=" p::clean($var->name), "module_name" => $var->module_name)) ?>"> + title=" $var->name, "module_name" => $var->module_name)) ?>"> value): ?> - value) ?> + value) ?> diff --git a/modules/gallery/views/admin_block_log_entries.html.php b/modules/gallery/views/admin_block_log_entries.html.php index 44c1657f..b7afb22d 100644 --- a/modules/gallery/views/admin_block_log_entries.html.php +++ b/modules/gallery/views/admin_block_log_entries.html.php @@ -2,7 +2,7 @@
                  • - user_id") ?>">user->name) ?> + user_id") ?>">user->name) ?> timestamp) ?> message ?> html ?> diff --git a/modules/gallery/views/admin_block_photo_stream.html.php b/modules/gallery/views/admin_block_photo_stream.html.php index 1e1329d1..732bdc38 100644 --- a/modules/gallery/views/admin_block_photo_stream.html.php +++ b/modules/gallery/views/admin_block_photo_stream.html.php @@ -2,9 +2,9 @@
                    • - id") ?>" title="title) ?>"> + id") ?>" title="title) ?>"> width, $photo->height, 72) ?> - src="thumb_url() ?>" alt="title) ?>" /> + src="thumb_url() ?>" alt="title) ?>" />
                    • diff --git a/modules/gallery/views/admin_maintenance.html.php b/modules/gallery/views/admin_maintenance.html.php index 450eb754..a4db38ce 100644 --- a/modules/gallery/views/admin_maintenance.html.php +++ b/modules/gallery/views/admin_maintenance.html.php @@ -90,7 +90,7 @@ status ?> - owner()->name) ?> + owner()->name) ?> state == "stalled"): ?> diff --git a/modules/gallery/views/admin_maintenance_show_log.html.php b/modules/gallery/views/admin_maintenance_show_log.html.php index 9d850986..209aef03 100644 --- a/modules/gallery/views/admin_maintenance_show_log.html.php +++ b/modules/gallery/views/admin_maintenance_show_log.html.php @@ -12,7 +12,7 @@ appendTo('body').submit().remove();

                      name ?>

                      -
                      get_log()) ?>
                      +
                      get_log()) ?>
                      diff --git a/modules/gallery/views/after_install.html.php b/modules/gallery/views/after_install.html.php index e4842163..2cf8ec8f 100644 --- a/modules/gallery/views/after_install.html.php +++ b/modules/gallery/views/after_install.html.php @@ -8,7 +8,7 @@

                      - %user_name account. The very first thing you should do is to change your password to something that you'll remember.", array("user_name" => p::clean($user->name))) ?> + %user_name account. The very first thing you should do is to change your password to something that you'll remember.", array("user_name" => $user->name)) ?>

                      diff --git a/modules/gallery/views/move_tree.html.php b/modules/gallery/views/move_tree.html.php index 5f70cf67..7818a42a 100644 --- a/modules/gallery/views/move_tree.html.php +++ b/modules/gallery/views/move_tree.html.php @@ -1,18 +1,18 @@ thumb_img(array(), 25); ?> is_descendant($parent)): ?> - title) ?> + title) ?> - title) ?> + title) ?>

                      • thumb_img(array(), 25); ?> is_descendant($child)): ?> - title) ?> + title) ?> - title) ?> + title) ?>
                      • diff --git a/modules/gallery/views/permissions_browse.html.php b/modules/gallery/views/permissions_browse.html.php index 888a27f7..9ea0da25 100644 --- a/modules/gallery/views/permissions_browse.html.php +++ b/modules/gallery/views/permissions_browse.html.php @@ -35,14 +35,14 @@
                      • - title) ?> + title) ?>
                        • - title) ?> + title) ?>
                          diff --git a/modules/gallery/views/permissions_form.html.php b/modules/gallery/views/permissions_form.html.php index ee5e3a24..adc0496f 100644 --- a/modules/gallery/views/permissions_form.html.php +++ b/modules/gallery/views/permissions_form.html.php @@ -6,7 +6,7 @@ - name) ?> + name) ?> diff --git a/modules/gallery/views/simple_uploader.html.php b/modules/gallery/views/simple_uploader.html.php index 38ac518c..56e568f6 100644 --- a/modules/gallery/views/simple_uploader.html.php +++ b/modules/gallery/views/simple_uploader.html.php @@ -6,7 +6,7 @@
                          ">
                          - p::purify($item->title))) ?> + SafeString::purify($item->title))) ?>
                          @@ -26,9 +26,9 @@

                            parents() as $parent): ?> -
                          • title) ?>
                          • +
                          • title) ?>
                          • -
                          • title) ?>
                          • +
                          • title) ?>

                          diff --git a/modules/info/views/info_block.html.php b/modules/info/views/info_block.html.php index f86ae39d..365a1021 100644 --- a/modules/info/views/info_block.html.php +++ b/modules/info/views/info_block.html.php @@ -2,18 +2,18 @@

                          diff --git a/modules/user/controllers/admin_users.php b/modules/user/controllers/admin_users.php index f87602b8..521f82fa 100644 --- a/modules/user/controllers/admin_users.php +++ b/modules/user/controllers/admin_users.php @@ -51,7 +51,7 @@ class Admin_Users_Controller extends Controller { $user->save(); module::event("user_add_form_admin_completed", $user, $form); - message::success(t("Created user %user_name", array("user_name" => p::clean($user->name)))); + message::success(t("Created user %user_name", array("user_name" => $user->name))); print json_encode(array("result" => "success")); } else { print json_encode(array("result" => "error", @@ -84,7 +84,7 @@ class Admin_Users_Controller extends Controller { "form" => $form->__toString())); } - $message = t("Deleted user %user_name", array("user_name" => p::clean($name))); + $message = t("Deleted user %user_name", array("user_name" => $name)); log::success("user", $message); message::success($message); print json_encode(array("result" => "success")); @@ -142,7 +142,7 @@ class Admin_Users_Controller extends Controller { $user->save(); module::event("user_edit_form_admin_completed", $user, $form); - message::success(t("Changed user %user_name", array("user_name" => p::clean($user->name)))); + message::success(t("Changed user %user_name", array("user_name" => $user->name))); print json_encode(array("result" => "success")); } else { print json_encode(array("result" => "error", @@ -204,7 +204,7 @@ class Admin_Users_Controller extends Controller { $group = group::create($new_name); $group->save(); message::success( - t("Created group %group_name", array("group_name" => p::clean($group->name)))); + t("Created group %group_name", array("group_name" => $group->name))); print json_encode(array("result" => "success")); } else { print json_encode(array("result" => "error", @@ -233,7 +233,7 @@ class Admin_Users_Controller extends Controller { "form" => $form->__toString())); } - $message = t("Deleted group %group_name", array("group_name" => p::clean($name))); + $message = t("Deleted group %group_name", array("group_name" => $name)); log::success("group", $message); message::success($message); print json_encode(array("result" => "success")); @@ -271,11 +271,11 @@ class Admin_Users_Controller extends Controller { $group->name = $form->edit_group->inputs["name"]->value; $group->save(); message::success( - t("Changed group %group_name", array("group_name" => p::clean($group->name)))); + t("Changed group %group_name", array("group_name" => $group->name))); print json_encode(array("result" => "success")); } else { message::error( - t("Failed to change group %group_name", array("group_name" => p::clean($group->name)))); + t("Failed to change group %group_name", array("group_name" => $group->name))); print json_encode(array("result" => "error", "form" => $form->__toString())); } diff --git a/modules/user/controllers/login.php b/modules/user/controllers/login.php index 4d901051..b81b17b2 100644 --- a/modules/user/controllers/login.php +++ b/modules/user/controllers/login.php @@ -63,7 +63,7 @@ class Login_Controller extends Controller { log::warning( "user", t("Failed login for %name", - array("name" => p::clean($form->login->inputs["name"]->value)))); + array("name" => $form->login->inputs["name"]->value))); $form->login->inputs["name"]->add_error("invalid_login", 1); $valid = false; } @@ -71,7 +71,7 @@ class Login_Controller extends Controller { if ($valid) { user::login($user); - log::info("user", t("User %name logged in", array("name" => p::clean($user->name)))); + log::info("user", t("User %name logged in", array("name" => $user->name))); } // Either way, regenerate the session id to avoid session trapping diff --git a/modules/user/controllers/logout.php b/modules/user/controllers/logout.php index 099b1952..4b141a1c 100644 --- a/modules/user/controllers/logout.php +++ b/modules/user/controllers/logout.php @@ -23,8 +23,8 @@ class Logout_Controller extends Controller { $user = user::active(); user::logout(); - log::info("user", t("User %name logged out", array("name" => p::clean($user->name))), - html::anchor("user/$user->id", p::clean($user->name))); + log::info("user", t("User %name logged out", array("name" => $user->name)), + html::anchor("user/$user->id", SafeString::of($user->name))); if ($continue_url = $this->input->get("continue")) { $item = url::get_item_from_uri($continue_url); if (access::can("view", $item)) { diff --git a/modules/user/controllers/password.php b/modules/user/controllers/password.php index 2af1b879..066efbba 100644 --- a/modules/user/controllers/password.php +++ b/modules/user/controllers/password.php @@ -74,7 +74,7 @@ class Password_Controller extends Controller { log::success( "user", - t("Password reset email sent for user %name", array("name" => p::clean($user->name)))); + t("Password reset email sent for user %name", array("name" => $user->name))); } else { // Don't include the username here until you're sure that it's XSS safe log::warning( diff --git a/modules/user/views/admin_users.html.php b/modules/user/views/admin_users.html.php index 542b8b8b..54c4847d 100644 --- a/modules/user/views/admin_users.html.php +++ b/modules/user/views/admin_users.html.php @@ -68,16 +68,16 @@ " title="" - alt="name) ?>" + alt="name) ?>" width="20" height="20" /> - name) ?> + name) ?> - full_name) ?> + full_name) ?> - email) ?> + email) ?> last_login == 0) ? "" : gallery::date($user->last_login) ?> diff --git a/modules/user/views/admin_users_group.html.php b/modules/user/views/admin_users_group.html.php index bfd79dba..f89a4392 100644 --- a/modules/user/views/admin_users_group.html.php +++ b/modules/user/views/admin_users_group.html.php @@ -1,9 +1,9 @@

                          - name) ?> + name) ?> special): ?> id") ?>" - title=" p::clean($group->name))) ?>" + title=" $group->name)) ?>" class="gDialogLink gButtonLink ui-state-default ui-corner-all"> @@ -17,12 +17,12 @@

                            @@ -16,7 +16,7 @@ width="thumb_width ?>" height="thumb_height ?>" /> -

                            title) ?>

                            +

                            title) ?>

                            thumb_bottom($child) ?> diff --git a/themes/default/views/movie.html.php b/themes/default/views/movie.html.php index 66c80ded..1f25a626 100644 --- a/themes/default/views/movie.html.php +++ b/themes/default/views/movie.html.php @@ -15,8 +15,8 @@ movie_img(array("class" => "gMovie", "id" => "gMovieId-{$item->id}")) ?>
                            -

                            title) ?>

                            -
                            description)) ?>
                            +

                            title) ?>

                            +
                            description)) ?>
                            diff --git a/modules/gallery/views/simple_uploader.html.php b/modules/gallery/views/simple_uploader.html.php index 56e568f6..fc426e8f 100644 --- a/modules/gallery/views/simple_uploader.html.php +++ b/modules/gallery/views/simple_uploader.html.php @@ -82,27 +82,26 @@ diff --git a/modules/organize/views/organize.html.php b/modules/organize/views/organize.html.php index 1182a887..d2f0aa8c 100644 --- a/modules/organize/views/organize.html.php +++ b/modules/organize/views/organize.html.php @@ -1,16 +1,16 @@ script("gallery.dialog.js") ?> script("superfish/js/superfish.js") ?> diff --git a/themes/default/views/movie.html.php b/themes/default/views/movie.html.php index 1f25a626..75d51eff 100644 --- a/themes/default/views/movie.html.php +++ b/themes/default/views/movie.html.php @@ -20,7 +20,7 @@
                      photo_bottom() ?>
                diff --git a/themes/default/views/page.html.php b/themes/default/views/page.html.php index ea2be37b..8d9f0caa 100644 --- a/themes/default/views/page.html.php +++ b/themes/default/views/page.html.php @@ -51,7 +51,7 @@ script("gallery.common.js") ?> script("gallery.dialog.js") ?> script("gallery.form.js") ?> diff --git a/themes/default/views/photo.html.php b/themes/default/views/photo.html.php index 1f92e9ba..fcf597cf 100644 --- a/themes/default/views/photo.html.php +++ b/themes/default/views/photo.html.php @@ -5,7 +5,7 @@ photo_bottom() ?>
                -- cgit v1.2.3 From f327b4ad38923d40fcd6540467604cb0f24cd8bf Mon Sep 17 00:00:00 2001 From: Andy Staudacher Date: Sat, 29 Aug 2009 14:24:52 -0700 Subject: Fix link in l10n UI (for SafeString changes) --- modules/gallery/controllers/admin_languages.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/gallery/controllers/admin_languages.php b/modules/gallery/controllers/admin_languages.php index 6dc242c6..68be709e 100644 --- a/modules/gallery/controllers/admin_languages.php +++ b/modules/gallery/controllers/admin_languages.php @@ -111,7 +111,7 @@ class Admin_Languages_Controller extends Admin_Controller { $group->input("api_key") ->label(empty($api_key) ? t("This is a unique key that will allow you to send translations to the remote server. To get your API key go to %server-link.", - array("server-link" => html::anchor($server_link))) + array("server-link" => SafeString::of_safe_html(html::anchor($server_link)))) : t("API Key")) ->value($api_key) ->error_messages("invalid", t("The API key you provided is invalid.")); -- cgit v1.2.3 From c4d5ecde66c7bffde2259b9815c050e6a4d8f333 Mon Sep 17 00:00:00 2001 From: Andy Staudacher Date: Sat, 29 Aug 2009 14:38:47 -0700 Subject: L10n fixes for the admin_languages page, and JS/XSS cleanup of the organize views. --- modules/gallery/views/admin_languages.html.php | 21 +++++++++++++-------- modules/organize/views/organize_dialog.html.php | 2 +- modules/organize/views/organize_tree.html.php | 6 +++--- 3 files changed, 17 insertions(+), 12 deletions(-) diff --git a/modules/gallery/views/admin_languages.html.php b/modules/gallery/views/admin_languages.html.php index 4025437a..4bee9bb1 100644 --- a/modules/gallery/views/admin_languages.html.php +++ b/modules/gallery/views/admin_languages.html.php @@ -36,11 +36,11 @@ - " /> + for_html_attr() ?>" />
                -

                p::purify($album->title))) ?>

                +

                SafeString::purify($album->title))) ?>

                diff --git a/modules/organize/views/organize_tree.html.php b/modules/organize/views/organize_tree.html.php index 36f900ac..387d5977 100644 --- a/modules/organize/views/organize_tree.html.php +++ b/modules/organize/views/organize_tree.html.php @@ -5,7 +5,7 @@ - title) ?> + title) ?>
                  @@ -17,7 +17,7 @@ " ref="id ?>"> - title) ?> + title) ?> id == $album->id): ?> @@ -29,7 +29,7 @@ - title) ?> + title) ?> -- cgit v1.2.3 From a5ddef021c1ca4920e40c0657de082ae0d7008ee Mon Sep 17 00:00:00 2001 From: Tim Almdal Date: Sat, 29 Aug 2009 15:03:46 -0700 Subject: Fix invalida syntax on trying to parse the progress bar percentage --- modules/gallery/views/admin_maintenance_task.html.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/gallery/views/admin_maintenance_task.html.php b/modules/gallery/views/admin_maintenance_task.html.php index 0eb0b38c..509e87b5 100644 --- a/modules/gallery/views/admin_maintenance_task.html.php +++ b/modules/gallery/views/admin_maintenance_task.html.php @@ -4,7 +4,7 @@ var animation = null; var delta = 1; animate_progress_bar = function() { - var current_value = Number($(".gProgressBar div").css("width").replace("%", "")); + var current_value = parseInt($(".gProgressBar div").css("width").replace("%", "")); if (target_value > current_value) { // speed up delta = Math.min(delta + 0.04, 3); -- cgit v1.2.3 From 0aceba6f48e5542d3edfbb1f195af50187adbac4 Mon Sep 17 00:00:00 2001 From: Tim Almdal Date: Sat, 29 Aug 2009 15:20:27 -0700 Subject: Fix for ticket #628: 1) increased gallery module version to 11 2) added image_sharpened parameter to the gallery module 3) sharpen all resizes. --- modules/gallery/helpers/gallery_installer.php | 9 ++++++++- modules/gallery/helpers/graphics.php | 5 +++++ modules/gallery/module.info | 2 +- 3 files changed, 14 insertions(+), 2 deletions(-) diff --git a/modules/gallery/helpers/gallery_installer.php b/modules/gallery/helpers/gallery_installer.php index a212ef85..40830bc0 100644 --- a/modules/gallery/helpers/gallery_installer.php +++ b/modules/gallery/helpers/gallery_installer.php @@ -223,6 +223,7 @@ class gallery_installer { module::set_var("gallery", "resize_size", 640); module::set_var("gallery", "default_locale", "en_US"); module::set_var("gallery", "image_quality", 75); + module::set_var("gallery", "image_sharpen", 15); // Add rules for generating our thumbnails and resizes graphics::add_rule( @@ -259,7 +260,7 @@ class gallery_installer { module::set_var("gallery", "show_credits", 1); // @todo this string needs to be picked up by l10n_scanner module::set_var("gallery", "credits", "Powered by Gallery %version"); - module::set_version("gallery", 10); + module::set_version("gallery", 11); } static function upgrade($version) { @@ -336,6 +337,12 @@ class gallery_installer { module::set_version("gallery", $version = 10); } + + if ($version == 10) { + module::set_var("gallery", "image_sharpen", 15); + + module::set_version("gallery", $version = 11); + } } static function uninstall() { diff --git a/modules/gallery/helpers/graphics.php b/modules/gallery/helpers/graphics.php index 7dc46eeb..2892011f 100644 --- a/modules/gallery/helpers/graphics.php +++ b/modules/gallery/helpers/graphics.php @@ -206,10 +206,15 @@ class graphics_Core { // Image would get upscaled; do nothing copy($input_file, $output_file); } else { + try { Image::factory($input_file) ->resize($options["width"], $options["height"], $options["master"]) ->quality(module::get_var("gallery", "image_quality")) + ->sharpen(module::get_var("gallery", "image_sharpen")) ->save($output_file); + } catch (Exception $e) { + Kohana::log("error", $e->getMessage()); + } } module::event("graphics_resize_completed", $input_file, $output_file, $options); diff --git a/modules/gallery/module.info b/modules/gallery/module.info index dfb1a7a2..6b9dd1ba 100644 --- a/modules/gallery/module.info +++ b/modules/gallery/module.info @@ -1,3 +1,3 @@ name = "Gallery 3" description = "Gallery core application" -version = 10 +version = 11 -- cgit v1.2.3 From 0204617b602183a3e157bc7e23c617acd22a5212 Mon Sep 17 00:00:00 2001 From: Andy Staudacher Date: Sat, 29 Aug 2009 15:41:02 -0700 Subject: XSS fixes --- modules/gallery/views/admin_maintenance.html.php | 2 +- modules/rss/views/rss_block.html.php | 2 +- modules/server_add/views/admin_server_add.html.php | 4 ++-- modules/server_add/views/server_add_tree.html.php | 4 ++-- modules/tag/views/admin_tags.html.php | 4 ++-- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/modules/gallery/views/admin_maintenance.html.php b/modules/gallery/views/admin_maintenance.html.php index a0a6a19e..a1f7b126 100644 --- a/modules/gallery/views/admin_maintenance.html.php +++ b/modules/gallery/views/admin_maintenance.html.php @@ -164,7 +164,7 @@ status ?> - owner()->name ?> + owner()->name) ?> done): ?> diff --git a/modules/rss/views/rss_block.html.php b/modules/rss/views/rss_block.html.php index 39921d7d..cd8db89d 100644 --- a/modules/rss/views/rss_block.html.php +++ b/modules/rss/views/rss_block.html.php @@ -5,7 +5,7 @@ - + diff --git a/modules/server_add/views/admin_server_add.html.php b/modules/server_add/views/admin_server_add.html.php index 30ab3536..c4439bda 100644 --- a/modules/server_add/views/admin_server_add.html.php +++ b/modules/server_add/views/admin_server_add.html.php @@ -11,12 +11,12 @@ diff --git a/modules/server_add/views/server_add_tree.html.php b/modules/server_add/views/server_add_tree.html.php index b68544ec..2f65a590 100644 --- a/modules/server_add/views/server_add_tree.html.php +++ b/modules/server_add/views/server_add_tree.html.php @@ -10,7 +10,7 @@
                • - +
                    @@ -22,7 +22,7 @@ ondblclick="open_dir($(this).attr('file'))" - file="" + file=" '\\"')) ?>" > diff --git a/modules/tag/views/admin_tags.html.php b/modules/tag/views/admin_tags.html.php index 5bd23112..30dd0728 100644 --- a/modules/tag/views/admin_tags.html.php +++ b/modules/tag/views/admin_tags.html.php @@ -32,7 +32,7 @@ name, 0, 1)) ?> - +
                      $tags_per_column): /* new column */ ?> @@ -42,7 +42,7 @@
                    - +
                      -- cgit v1.2.3 From 60cfa54b828b28b93473d583b8d00f8e9a87c691 Mon Sep 17 00:00:00 2001 From: Chad Kieffer Date: Sat, 29 Aug 2009 17:02:43 -0600 Subject: Fix error text color. --- themes/default/css/screen.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/themes/default/css/screen.css b/themes/default/css/screen.css index 82cdb331..5eb30bde 100644 --- a/themes/default/css/screen.css +++ b/themes/default/css/screen.css @@ -308,7 +308,7 @@ li.gError select { .gError { background-color: #f6cbca; - color: #fc0; + color: #f00; background-image: url('../images/ico-error.png'); } -- cgit v1.2.3 From 39559fdfd09491dce669d0351768fe2b13ccdd03 Mon Sep 17 00:00:00 2001 From: jhilden Date: Sat, 29 Aug 2009 19:11:16 -0400 Subject: initial version of the the file with common CSS styles that should be reused if possible --- lib/gallery.common.css | 111 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 111 insertions(+) create mode 100644 lib/gallery.common.css diff --git a/lib/gallery.common.css b/lib/gallery.common.css new file mode 100644 index 00000000..ca90a484 --- /dev/null +++ b/lib/gallery.common.css @@ -0,0 +1,111 @@ +/* ####### states, interactions, positioning ########### */ + +/* states */ + +.g-active, .g-enabled, .g-available, .g-editable, .g-selected, .g-highlight { + font-weight: bold; +} +.g-inactive, .g-disabled, .g-unavailable, .g-uneditable, .g-locked, .g-unselected, .g-understate { + color: #ccc; + font-weight: normal; +} + +.g-error, .g-denied { + +} +.g-success, .g-allowed { + +} +.g-info { + +} +.g-warning { + +} + +.g-open { + +} +.g-closed { + +} + +.g-installed { + +} +.g-default { + +} + +/* interactions */ + +.g-draggable, .ui-draggable { + cursor: move; +} +.g-target { + +} + + + +/* positioning */ + +.g-right { + float: right; +} +.g-left { + float: left; +} + +/* order */ + +.g-first { + +} +.g-last { + +} +.g-even-row { + +} +.g-odd-row { + +} + +/* text */ + +.g-txt-small { + font-size: .8em; +} +.g-txt-big { + font-size: 1.2em; +} +.g-txt-right { + text-align: right; +} + +/* ####### reusable containers/widgets ########### */ + +.g-dialog { + +} + +.g-button { /* a link styled like a button */ + +} + +.g-progressbar { + +} + +.g-block { + +} + +.g-message-box { + +} + +.g-list-horizontal { + +} -- cgit v1.2.3 From a1ce2d3f0aff6dcb7149f2d7327a10079e5c78f8 Mon Sep 17 00:00:00 2001 From: jhilden Date: Sat, 29 Aug 2009 19:19:04 -0400 Subject: you can close the l10n client directly from its interface now, without going back to the languages admin page --- modules/gallery/js/l10n_client.js | 13 +++++++++++++ modules/gallery/views/l10n_client.html.php | 5 ++++- 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/modules/gallery/js/l10n_client.js b/modules/gallery/js/l10n_client.js index 80fe166b..35986e5a 100644 --- a/modules/gallery/js/l10n_client.js +++ b/modules/gallery/js/l10n_client.js @@ -205,6 +205,19 @@ Gallery.behaviors.l10nClient = function(context) { Gallery.l10nClient.toggle(0); } }); + + // Close the l10n client using an AJAX call and refreshing the page + $('#gCloseL10n').click(function(event) { + $.ajax({ + type: "GET", + url: toggle_l10n_mode_url, + data: "csrf=" + csrf, + success: function() { + window.location.reload(true); + } + }); + event.preventDefault(); + }); // Register keybindings using jQuery hotkeys // TODO: Either remove hotkeys code or add query.hotkeys.js. diff --git a/modules/gallery/views/l10n_client.html.php b/modules/gallery/views/l10n_client.html.php index 5ee7eca3..6c440b68 100644 --- a/modules/gallery/views/l10n_client.html.php +++ b/modules/gallery/views/l10n_client.html.php @@ -3,7 +3,8 @@
                      _ - X + " + href="">X

                      get('show_all_l10n_messages')): ?> @@ -76,5 +77,7 @@ var MSG_CLOSE_X = ""; var l10n_client_data = ; var plural_forms = ; + var toggle_l10n_mode_url = ""; + var csrf = "";

                      -- cgit v1.2.3 From b4b638be44375c93f5222c7b48ed547845d6d7e5 Mon Sep 17 00:00:00 2001 From: Andy Staudacher Date: Sat, 29 Aug 2009 16:28:30 -0700 Subject: Undo url helper changes - url methods no longer return a SafeString. Adding SafeString::of_safe_html() calls where urls are passed as parameters to t() and t2(). --- modules/akismet/helpers/akismet.php | 2 +- modules/digibug/views/admin_digibug.html.php | 2 +- modules/exif/helpers/exif.php | 2 +- modules/g2_import/views/admin_g2_import.html.php | 10 ++++----- modules/gallery/helpers/MY_url.php | 24 +--------------------- modules/gallery/helpers/graphics.php | 2 +- modules/gallery/tests/Xss_Security_Test.php | 15 +++++++++++--- modules/gallery/views/admin_block_welcome.html.php | 10 ++++----- modules/gallery/views/upgrader.html.php | 2 +- modules/recaptcha/helpers/recaptcha.php | 2 +- modules/search/helpers/search.php | 2 +- modules/server_add/helpers/server_add.php | 2 +- modules/user/views/reset_password.html.php | 4 +++- system/helpers/request.php | 2 +- 14 files changed, 35 insertions(+), 46 deletions(-) diff --git a/modules/akismet/helpers/akismet.php b/modules/akismet/helpers/akismet.php index db45a6ab..abca78d2 100644 --- a/modules/akismet/helpers/akismet.php +++ b/modules/akismet/helpers/akismet.php @@ -94,7 +94,7 @@ class akismet_Core { if (empty($api_key)) { site_status::warning( t("Akismet is not quite ready! Please provide an API Key", - array("url" => url::site("admin/akismet"))), + array("url" => SafeString::of_safe_html(url::site("admin/akismet")))), "akismet_config"); } else { site_status::clear("akismet_config"); diff --git a/modules/digibug/views/admin_digibug.html.php b/modules/digibug/views/admin_digibug.html.php index 7e4436ff..5f27a3fd 100644 --- a/modules/digibug/views/admin_digibug.html.php +++ b/modules/digibug/views/admin_digibug.html.php @@ -16,7 +16,7 @@

                      register with Digibug and enter your Digibug id in the Advanced Settings page you can make money off of your photos!", array("signup_url" => "http://www.digibug.com/signup.php", - "advanced_settings_url" => url::site("admin/advanced_settings"))) ?> + "advanced_settings_url" => SafeString::of_safe_html(url::site("admin/advanced_settings")))) ?>

                diff --git a/modules/exif/helpers/exif.php b/modules/exif/helpers/exif.php index 20ecd0cb..d4e60338 100644 --- a/modules/exif/helpers/exif.php +++ b/modules/exif/helpers/exif.php @@ -164,7 +164,7 @@ class exif_Core { if ($remaining) { site_status::warning( t('Your Exif index needs to be updated. Fix this now', - array("url" => url::site("admin/maintenance/start/exif_task::update_index?csrf=__CSRF__"))), + array("url" => SafeString::of_safe_html(url::site("admin/maintenance/start/exif_task::update_index?csrf=__CSRF__")))), "exif_index_out_of_date"); } } diff --git a/modules/g2_import/views/admin_g2_import.html.php b/modules/g2_import/views/admin_g2_import.html.php index da2bb5d1..f53510f6 100644 --- a/modules/g2_import/views/admin_g2_import.html.php +++ b/modules/g2_import/views/admin_g2_import.html.php @@ -37,9 +37,9 @@
              • Using the same value will speed up your import.", - array("g2_pixels" => $g2_sizes["thumb"]["size"], - "g3_pixels" => $thumb_size, - "url" => url::site("admin/theme_options"))) ?> + array("g2_pixels" => $g2_sizes["thumb"]["size"], + "g3_pixels" => $thumb_size, + "url" => SafeString::of_safe_html(url::site("admin/theme_options")))) ?>
              • @@ -47,8 +47,8 @@
              • Using the same value will speed up your import.", array("g2_pixels" => $g2_sizes["resize"]["size"], - "g3_pixels" => $resize_size, - "url" => url::site("admin/theme_options"))) ?> + "g3_pixels" => $resize_size, + "url" => SafeString::of_safe_html(url::site("admin/theme_options")))) ?>
              • diff --git a/modules/gallery/helpers/MY_url.php b/modules/gallery/helpers/MY_url.php index 6092a9d8..c4967c52 100644 --- a/modules/gallery/helpers/MY_url.php +++ b/modules/gallery/helpers/MY_url.php @@ -30,8 +30,7 @@ class url extends url_Core { if ($parts[0] == "albums" || $parts[0] == "photos") { $uri = model_cache::get("item", $parts[1])->relative_path(); } - $url = parent::site($uri . $query, $protocol); - return SafeString::of_safe_html($url); + return parent::site($uri . $query, $protocol); } static function parse_url() { @@ -100,25 +99,4 @@ class url extends url_Core { static function abs_current($qs=false) { return self::abs_site(url::current($qs)); } - - public static function base($index=false, $protocol=false) { - $url = parent::base($index, $protocol); - return SafeString::of_safe_html($url); - } - - public static function current($qs=false) { - $url = parent::current($qs); - return SafeString::of_safe_html($url); - } - - public static function file($file, $index=false) { - $url = parent::file($file, $index); - return SafeString::of_safe_html($url); - } - - public static function merge(array $arguments) { - $url = parent::merge($arguments); - return SafeString::of_safe_html($url); - } - } diff --git a/modules/gallery/helpers/graphics.php b/modules/gallery/helpers/graphics.php index 7dc46eeb..fbb85bec 100644 --- a/modules/gallery/helpers/graphics.php +++ b/modules/gallery/helpers/graphics.php @@ -442,7 +442,7 @@ class graphics_Core { if (!module::get_var("gallery", "graphics_toolkit")) { site_status::warning( t("Graphics toolkit missing! Please choose a toolkit", - array("url" => url::site("admin/graphics"))), + array("url" => SafeString::of_safe_html(url::site("admin/graphics")))), "missing_graphics_toolkit"); } } diff --git a/modules/gallery/tests/Xss_Security_Test.php b/modules/gallery/tests/Xss_Security_Test.php index 690dc760..a2d3d59b 100644 --- a/modules/gallery/tests/Xss_Security_Test.php +++ b/modules/gallery/tests/Xss_Security_Test.php @@ -130,14 +130,14 @@ class Xss_Security_Test extends Unit_Test_Case { $token = $tokens[$token_number]; } } else if ($token[1] == "url") { - // url methods return a SafeString + // url methods return safe HTML if (self::_token_matches(array(T_DOUBLE_COLON, "::"), $tokens, $token_number + 1) && self::_token_matches(array(T_STRING), $tokens, $token_number + 2) && in_array($tokens[$token_number + 2][1], array("site", "current", "base", "file", "abs_site", "abs_current", "abs_file", "merge")) && self::_token_matches("(", $tokens, $token_number + 3)) { - $frame->is_safestring(true); + $frame->is_safe_html(true); $method = $tokens[$token_number + 2][1]; $frame->expr_append("::$method("); @@ -203,7 +203,8 @@ class Xss_Security_Test extends Unit_Test_Case { $state = "CLEAN"; } } else { - if ($frame->is_safestring() || $frame->purified_html_called() || $frame->for_html_called()) { + if ($frame->is_safe_html() || $frame->is_safestring() || + $frame->purified_html_called() || $frame->for_html_called()) { $state = "CLEAN"; } } @@ -259,6 +260,7 @@ class Xss_Security_Test_Frame { private $_for_html_called = false; private $_purified_html_called = false; private $_json_encode_called = false; + private $_is_safe_html = false; private $_line; function __construct($line_number, $in_script_block) { @@ -288,6 +290,13 @@ class Xss_Security_Test_Frame { return $this->_is_safestring; } + function is_safe_html($new_val=NULL) { + if ($new_val !== NULL) { + $this->_is_safe_html = (bool) $new_val; + } + return $this->_is_safe_html; + } + function json_encode_called($new_val=NULL) { if ($new_val !== NULL) { $this->_json_encode_called = (bool) $new_val; diff --git a/modules/gallery/views/admin_block_welcome.html.php b/modules/gallery/views/admin_block_welcome.html.php index 38d2bd56..c6ccdbf3 100644 --- a/modules/gallery/views/admin_block_welcome.html.php +++ b/modules/gallery/views/admin_block_welcome.html.php @@ -5,16 +5,16 @@
                • graphics and language settings.", - array("graphics_url" => url::site("admin/graphics"), - "language_url" => url::site("admin/languages"))) ?> + array("graphics_url" => SafeString::of_safe_html(url::site("admin/graphics")), + "language_url" => SafeString::of_safe_html(url::site("admin/languages")))) ?>
                • choose a theme, or customize the way it looks.", - array("theme_url" => url::site("admin/themes"), - "theme_options_url" => url::site("admin/theme_options"))) ?> + array("theme_url" => SafeString::of_safe_html(url::site("admin/themes")), + "theme_options_url" => SafeString::of_safe_html(url::site("admin/theme_options")))) ?>
                • install modules to add cool features!", - array("modules_url" => url::site("admin/modules"))) ?> + array("modules_url" => SafeString::of_safe_html(url::site("admin/modules")))) ?>
                diff --git a/modules/gallery/views/upgrader.html.php b/modules/gallery/views/upgrader.html.php index 37578855..ccc86da8 100644 --- a/modules/gallery/views/upgrader.html.php +++ b/modules/gallery/views/upgrader.html.php @@ -18,7 +18,7 @@

                Gallery is up to date.", - array("url" => url::site("albums/1"))) ?> + array("url" => SafeString::of_safe_html(url::site("albums/1")))) ?>

                diff --git a/modules/recaptcha/helpers/recaptcha.php b/modules/recaptcha/helpers/recaptcha.php index 501dd972..35d9febd 100644 --- a/modules/recaptcha/helpers/recaptcha.php +++ b/modules/recaptcha/helpers/recaptcha.php @@ -43,7 +43,7 @@ class recaptcha_Core { if (empty($public_key) || empty($private_key)) { site_status::warning( t("reCAPTCHA is not quite ready! Please configure the reCAPTCHA Keys", - array("url" => url::site("admin/recaptcha"))), + array("url" => SafeString::of_safe_html(url::site("admin/recaptcha")))), "recaptcha_config"); } else { site_status::clear("recaptcha_config"); diff --git a/modules/search/helpers/search.php b/modules/search/helpers/search.php index 355c4493..4be04039 100644 --- a/modules/search/helpers/search.php +++ b/modules/search/helpers/search.php @@ -58,7 +58,7 @@ class search_Core { if ($remaining) { site_status::warning( t('Your search index needs to be updated. Fix this now', - array("url" => url::site("admin/maintenance/start/search_task::update_index?csrf=__CSRF__"))), + array("url" => SafeString::of_safe_html(url::site("admin/maintenance/start/search_task::update_index?csrf=__CSRF__")))), "search_index_out_of_date"); } } diff --git a/modules/server_add/helpers/server_add.php b/modules/server_add/helpers/server_add.php index 74f51ad9..57afac12 100644 --- a/modules/server_add/helpers/server_add.php +++ b/modules/server_add/helpers/server_add.php @@ -25,7 +25,7 @@ class server_add_Core { if (empty($paths)) { site_status::warning( t("Server Add needs configuration. Configure it now!", - array("url" => url::site("admin/server_add"))), + array("url" => SafeString::of_safe_html(url::site("admin/server_add")))), "server_add_configuration"); } else { site_status::clear("server_add_configuration"); diff --git a/modules/user/views/reset_password.html.php b/modules/user/views/reset_password.html.php index 3dc7aebf..6fa92d54 100644 --- a/modules/user/views/reset_password.html.php +++ b/modules/user/views/reset_password.html.php @@ -9,7 +9,9 @@ $user->full_name ? $user->full_name : $user->name)) ?>

                - %site_url. If you made this request, you can confirm it by clicking this link. If you didn't request this password reset, it's ok to ignore this mail.", array("site_url" => url::base(false, "http"), "confirm_url" => $confirm_url)) ?> + %site_url. If you made this request, you can confirm it by clicking this link. If you didn't request this password reset, it's ok to ignore this mail.", + array("site_url" => SafeString::of_safe_html(url::base(false, "http")), + "confirm_url" => $confirm_url)) ?>

                diff --git a/system/helpers/request.php b/system/helpers/request.php index 15b8edfa..4203d0e5 100644 --- a/system/helpers/request.php +++ b/system/helpers/request.php @@ -30,7 +30,7 @@ class request_Core { // Set referrer $ref = $_SERVER['HTTP_REFERER']; - if (strpos($ref, (string) url::base(FALSE)) === 0) + if (strpos($ref, url::base(FALSE)) === 0) { // Remove the base URL from the referrer $ref = substr($ref, strlen(url::base(FALSE))); -- cgit v1.2.3 From 75ee962c9e1b6a0c24928f80245430db71780a3d Mon Sep 17 00:00:00 2001 From: Chad Kieffer Date: Sat, 29 Aug 2009 17:32:34 -0600 Subject: Apply hover effect to dialog buttons. --- lib/gallery.dialog.js | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/gallery.dialog.js b/lib/gallery.dialog.js index 67f3f02d..39c451e3 100644 --- a/lib/gallery.dialog.js +++ b/lib/gallery.dialog.js @@ -76,6 +76,7 @@ var eCancel = '' + MSG_CANCEL + ''; if ($("#gDialog .submit").length) { $("#gDialog .submit").addClass("ui-state-default ui-corner-all"); + $.fn.gallery_hover_init(); $("#gDialog .submit").parent().append(eCancel); $("#gDialog .gCancel").click(function(event) { $("#gDialog").dialog("close"); -- cgit v1.2.3 From 483d8df91b443a20a614eb5864cabb2a66ac72d2 Mon Sep 17 00:00:00 2001 From: Bharat Mediratta Date: Sat, 29 Aug 2009 16:33:22 -0700 Subject: Change the organize tree to expand/collapse. It doesn't properly open up to the album that you're viewing, and if you move a photo to a different album it'll reload the entire album tree. --- modules/organize/controllers/organize.php | 18 +++++----- modules/organize/js/organize.js | 26 ++++++++++++++ modules/organize/views/organize_dialog.html.php | 1 + modules/organize/views/organize_tree.html.php | 46 +++++++------------------ 4 files changed, 47 insertions(+), 44 deletions(-) diff --git a/modules/organize/controllers/organize.php b/modules/organize/controllers/organize.php index 2b966657..3cbcfb28 100644 --- a/modules/organize/controllers/organize.php +++ b/modules/organize/controllers/organize.php @@ -25,7 +25,7 @@ class Organize_Controller extends Controller { $v = new View("organize_dialog.html"); $v->album = $album; - $v->album_tree = self::_tree($album); + $v->album_tree = self::_tree(ORM::factory("item", 1)); $v->micro_thumb_grid = self::_get_micro_thumb_grid($album, 0); print $v; } @@ -50,7 +50,7 @@ class Organize_Controller extends Controller { } print json_encode( - array("tree" => self::_tree($album)->__toString(), + array("tree" => self::_tree(ORM::factory("item", 1))->__toString(), "grid" => self::_get_micro_thumb_grid($album, 0)->__toString())); } @@ -132,17 +132,15 @@ class Organize_Controller extends Controller { return $v; } + public function tree($album_id) { + $album = ORM::factory("item", $album_id); + access::required("view", $album); + print self::_tree($album); + } + private static function _tree($album) { $v = new View("organize_tree.html"); - $v->parents = $album->parents(); $v->album = $album; - - if ($album->id == 1) { - $v->peers = array($album); - } else { - $v->peers = $album->parent()->children(null, 0, array("type" => "album")); - } - return $v; } } diff --git a/modules/organize/js/organize.js b/modules/organize/js/organize.js index 04e14a2f..3dbd0c89 100644 --- a/modules/organize/js/organize.js +++ b/modules/organize/js/organize.js @@ -159,8 +159,34 @@ $(".gMicroThumbGridCell").mousemove($.organize.mouse_move_handler); $(".gOrganizeAlbum").droppable($.organize.branch_droppable); $(".gAlbumText").click($.organize.show_album); + $("#gOrganizeAlbumTree .ui-icon-plus,#gOrganizeAlbumTree .ui-icon-minus").click($.organize.toggle_branch); }, + toggle_branch: function(event) { + event.preventDefault(); + var target = $(event.currentTarget); + var branch = $(target).parent(); + var id = $(event.currentTarget).parent().attr("ref"); + + if ($(target).hasClass("ui-icon-plus")) { + // Expanding + if (!branch.find("ul").length) { + $.get(tree_url.replace("__ALBUM_ID__", id), { }, + function(data) { + branch.replaceWith(data); + $.organize.set_handlers(); + } + ); + } else { + branch.find("ul:eq(0)").slideDown(); + } + } else { + // Contracting + branch.find("ul:eq(0)").slideUp(); + } + $(target).toggleClass("ui-icon-plus"); + $(target).toggleClass("ui-icon-minus"); + }, /** * When the text of a selection is clicked, then show that albums contents diff --git a/modules/organize/views/organize_dialog.html.php b/modules/organize/views/organize_dialog.html.php index b03c066c..d4196460 100644 --- a/modules/organize/views/organize_dialog.html.php +++ b/modules/organize/views/organize_dialog.html.php @@ -3,6 +3,7 @@ var move_url = ""; var rearrange_url = ""; var sort_order_url = ""; + var tree_url = "";

                p::purify($album->title))) ?>

                diff --git a/modules/organize/views/organize_tree.html.php b/modules/organize/views/organize_tree.html.php index 36f900ac..4677234c 100644 --- a/modules/organize/views/organize_tree.html.php +++ b/modules/organize/views/organize_tree.html.php @@ -1,44 +1,22 @@ - -
              • " - ref="id ?>"> +
              • " + ref="id ?>"> - - title) ?> + + title) ?> -
                  - - - -
                • " - ref="id ?>"> - "> +
                    + children(null, 0, array("type" => "album")) as $child): ?> +
                  • " + ref="id ?>"> + - " - ref="id ?>"> - title) ?> + + title) ?> - - id == $album->id): ?> -
                      - children(null, 0, array("type" => "album")) as $child): ?> -
                    • " - ref="id ?>"> - - - - title) ?> - -
                    • - -
                    -
                  • - -
                • - + -- cgit v1.2.3 From 878b9c91b234f464eb9e1a3bdfbd0e6285a1a0e7 Mon Sep 17 00:00:00 2001 From: Bharat Mediratta Date: Sat, 29 Aug 2009 16:38:53 -0700 Subject: Remove try/catch in resize() since that will swallow any exceptions that we generate when resizing. --- modules/gallery/helpers/graphics.php | 4 ---- 1 file changed, 4 deletions(-) diff --git a/modules/gallery/helpers/graphics.php b/modules/gallery/helpers/graphics.php index 2892011f..a20c58dd 100644 --- a/modules/gallery/helpers/graphics.php +++ b/modules/gallery/helpers/graphics.php @@ -206,15 +206,11 @@ class graphics_Core { // Image would get upscaled; do nothing copy($input_file, $output_file); } else { - try { Image::factory($input_file) ->resize($options["width"], $options["height"], $options["master"]) ->quality(module::get_var("gallery", "image_quality")) ->sharpen(module::get_var("gallery", "image_sharpen")) ->save($output_file); - } catch (Exception $e) { - Kohana::log("error", $e->getMessage()); - } } module::event("graphics_resize_completed", $input_file, $output_file, $options); -- cgit v1.2.3 From 4bc7165dab267311407294b11a77e6c2689ad4a1 Mon Sep 17 00:00:00 2001 From: Bharat Mediratta Date: Sat, 29 Aug 2009 16:42:33 -0700 Subject: Delete obsolete comment and tighten the code in site_menu(). --- modules/server_add/helpers/server_add_event.php | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/modules/server_add/helpers/server_add_event.php b/modules/server_add/helpers/server_add_event.php index 6b21ec2e..b9dd8c28 100644 --- a/modules/server_add/helpers/server_add_event.php +++ b/modules/server_add/helpers/server_add_event.php @@ -31,15 +31,11 @@ class server_add_event_Core { $paths = unserialize(module::get_var("server_add", "authorized_paths")); if ($item && user::active()->admin && $item->is_album() && !empty($paths)) { - // This is a little tricky. Normally there's an "Add Photo" menu option, but we want to - // turn that into a dropdown if there are two different ways to add things. Do that in a - // portable way for now. If we find ourselves duplicating this pattern, we should make an - // API method for this. - $add_menu = $menu->get("add_menu"); - $add_menu->append(Menu::factory("dialog") - ->id("server_add") - ->label(t("Server add")) - ->url(url::site("server_add/browse/$item->id"))); + $menu->get("add_menu") + ->append(Menu::factory("dialog") + ->id("server_add") + ->label(t("Server add")) + ->url(url::site("server_add/browse/$item->id"))); } } } -- cgit v1.2.3 From 952c8856098dcfd9673d344fc71be85b303c8fb1 Mon Sep 17 00:00:00 2001 From: Andy Staudacher Date: Sat, 29 Aug 2009 22:31:23 -0700 Subject: Adding html::clean(), ::purify(), etc. --- modules/gallery/helpers/MY_html.php | 91 +++++++++++++++++++++++++++++ modules/gallery/tests/Html_Helper_Test.php | 55 +++++++++++++++++ modules/gallery/tests/Xss_Security_Test.php | 86 ++++++++++++--------------- 3 files changed, 182 insertions(+), 50 deletions(-) create mode 100644 modules/gallery/helpers/MY_html.php create mode 100644 modules/gallery/tests/Html_Helper_Test.php diff --git a/modules/gallery/helpers/MY_html.php b/modules/gallery/helpers/MY_html.php new file mode 100644 index 00000000..eb388811 --- /dev/null +++ b/modules/gallery/helpers/MY_html.php @@ -0,0 +1,91 @@ + + *
                  + * + */ + static function clean($html) { + return new SafeString($html); + } + + /** + * Returns a string that is safe to be used in HTML (XSS protection), + * purifying (filtering) the given HTML to ensure that the result contains + * only non-malicious HTML. + * + * Example:
                  +   *   
                  title) ?> + *
                  + */ + static function purify($html) { + return SafeString::purify($html); + } + + /** + * Flags the given string as safe to be used in HTML (free of malicious HTML/JS). + * + * Example:
                  +   *   // Parameters to t() are automatically escaped by default.
                  +   *   // If the parameter is marked as safe, it won't get escaped.
                  +   *   t('Go there',
                  +   *     array("url" => html::mark_safe(url::current())))
                  +   * 
                  + */ + static function mark_safe($html) { + return SafeString::of_safe_html($html); + } + + /** + * Escapes the given string for use in JavaScript. + * + * Example:
                  +   *   
                  +   * 
                  + * @return the string escaped for use in HTML attributes. + */ + static function clean_attribute($string) { + return self::clean($string)->for_html_attr(); + } +} diff --git a/modules/gallery/tests/Html_Helper_Test.php b/modules/gallery/tests/Html_Helper_Test.php new file mode 100644 index 00000000..4d934ad5 --- /dev/null +++ b/modules/gallery/tests/Html_Helper_Test.php @@ -0,0 +1,55 @@ +world

                  "); + $this->assert_equal("hello <p >world</p>", + $safe_string); + $this->assert_true($safe_string instanceof SafeString); + } + + public function purify_test() { + $safe_string = html::purify("hello

                  world

                  "); + $this->assert_equal("hello

                  world

                  ", + $safe_string); + $this->assert_true($safe_string instanceof SafeString); + } + + public function mark_safe_test() { + $safe_string = html::mark_safe("hello

                  world

                  "); + $this->assert_true($safe_string instanceof SafeString); + $safe_string_2 = html::clean($safe_string); + $this->assert_equal("hello

                  world

                  ", + $safe_string_2); + } + + public function escape_for_js_test() { + $string = html::escape_for_js("hello's

                  world

                  "); + $this->assert_equal("hello\\'s

                  world<\\/p>", + $string); + } + + public function clean_attribute_test() { + $safe_string = SafeString::of_safe_html("hello's

                  world

                  "); + $safe_string = html::clean_attribute($safe_string); + $this->assert_equal("hello's

                  world

                  ", + $safe_string); + } +} \ No newline at end of file diff --git a/modules/gallery/tests/Xss_Security_Test.php b/modules/gallery/tests/Xss_Security_Test.php index a2d3d59b..8e5f8354 100644 --- a/modules/gallery/tests/Xss_Security_Test.php +++ b/modules/gallery/tests/Xss_Security_Test.php @@ -101,7 +101,7 @@ class Xss_Security_Test extends Unit_Test_Case { // t() and t2() are special in that they're guaranteed to return a SafeString(). if (in_array($token[1], array("t", "t2"))) { if (self::_token_matches("(", $tokens, $token_number + 1)) { - $frame->is_safestring(true); + $frame->is_safe_html(true); $frame->expr_append("("); $token_number++; @@ -111,9 +111,11 @@ class Xss_Security_Test extends Unit_Test_Case { // Looking for SafeString::of(... if (self::_token_matches(array(T_DOUBLE_COLON, "::"), $tokens, $token_number + 1) && self::_token_matches(array(T_STRING), $tokens, $token_number + 2) && - in_array($tokens[$token_number + 2][1], array("of", "of_safe_html", "purify")) && + in_array($tokens[$token_number + 2][1], array("of", "purify")) && self::_token_matches("(", $tokens, $token_number + 3)) { - $frame->is_safestring(true); + // Not checking for of_safe_html(). We want such calls to be marked dirty (thus reviewed). + + $frame->is_safe_html(true); $method = $tokens[$token_number + 2][1]; $frame->expr_append("::$method("); @@ -123,7 +125,7 @@ class Xss_Security_Test extends Unit_Test_Case { } } else if ($token[1] == "json_encode") { if (self::_token_matches("(", $tokens, $token_number + 1)) { - $frame->json_encode_called(true); + $frame->is_safe_js(true); $frame->expr_append("("); $token_number++; @@ -145,15 +147,34 @@ class Xss_Security_Test extends Unit_Test_Case { $token_number += 3; $token = $tokens[$token_number]; } + } else if ($token[1] == "html") { + if (self::_token_matches(array(T_DOUBLE_COLON, "::"), $tokens, $token_number + 1) && + self::_token_matches(array(T_STRING), $tokens, $token_number + 2) && + in_array($tokens[$token_number + 2][1], + array("clean", "purify", "escape_for_js", "clean_attribute_test")) && + self::_token_matches("(", $tokens, $token_number + 3)) { + // Not checking for mark_safe(). We want such calls to be marked dirty (thus reviewed). + + $method = $tokens[$token_number + 2][1]; + $frame->expr_append("::$method("); + + $token_number += 3; + $token = $tokens[$token_number]; + + if ("escape_for_js" == $method) { + $frame->is_safe_js(true); + } else { + $frame->is_safe_html(true); + } + } } } else if ($frame && $token[0] == T_OBJECT_OPERATOR) { $frame->expr_append($token[1]); if (self::_token_matches(array(T_STRING), $tokens, $token_number + 1) && in_array($tokens[$token_number + 1][1], - array("for_js", "for_html", "purified_html")) && + array("for_js", "for_html", "purified_html", "for_html_attr")) && self::_token_matches("(", $tokens, $token_number + 2)) { - $method = $tokens[$token_number + 1][1]; $frame->expr_append("$method("); @@ -161,11 +182,9 @@ class Xss_Security_Test extends Unit_Test_Case { $token = $tokens[$token_number]; if ("for_js" == $method) { - $frame->for_js_called(true); - } else if ("for_html" == $method) { - $frame->for_html_called(true); - } else if ("purified_html" == $method) { - $frame->purified_html_called(true); + $frame->is_safe_js(true); + } else { + $frame->is_safe_html(true); } } } else if ($frame) { @@ -199,12 +218,11 @@ class Xss_Security_Test extends Unit_Test_Case { $state = "DIRTY"; if ($frame->in_script_block()) { $state = "DIRTY_JS"; - if ($frame->for_js_called() || $frame->json_encode_called()) { + if ($frame->is_safe_js()) { $state = "CLEAN"; } } else { - if ($frame->is_safe_html() || $frame->is_safestring() || - $frame->purified_html_called() || $frame->for_html_called()) { + if ($frame->is_safe_html()) { $state = "CLEAN"; } } @@ -255,12 +273,8 @@ class Xss_Security_Test extends Unit_Test_Case { class Xss_Security_Test_Frame { private $_expr = ""; private $_in_script_block = false; - private $_is_safestring = false; - private $_for_js_called = false; - private $_for_html_called = false; - private $_purified_html_called = false; - private $_json_encode_called = false; private $_is_safe_html = false; + private $_is_safe_js = false; private $_line; function __construct($line_number, $in_script_block) { @@ -283,13 +297,6 @@ class Xss_Security_Test_Frame { return $this->_in_script_block; } - function is_safestring($new_val=NULL) { - if ($new_val !== NULL) { - $this->_is_safestring = (bool) $new_val; - } - return $this->_is_safestring; - } - function is_safe_html($new_val=NULL) { if ($new_val !== NULL) { $this->_is_safe_html = (bool) $new_val; @@ -297,32 +304,11 @@ class Xss_Security_Test_Frame { return $this->_is_safe_html; } - function json_encode_called($new_val=NULL) { - if ($new_val !== NULL) { - $this->_json_encode_called = (bool) $new_val; - } - return $this->_json_encode_called; - } - - function for_js_called($new_val=NULL) { - if ($new_val !== NULL) { - $this->_for_js_called = (bool) $new_val; - } - return $this->_for_js_called; - } - - function for_html_called($new_val=NULL) { - if ($new_val !== NULL) { - $this->_for_html_called = (bool) $new_val; - } - return $this->_for_html_called; - } - - function purified_html_called($new_val=NULL) { + function is_safe_js($new_val=NULL) { if ($new_val !== NULL) { - $this->_purified_html_called = (bool) $new_val; + $this->_is_safe_js = (bool) $new_val; } - return $this->_purified_html_called; + return $this->_is_safe_js; } function line() { -- cgit v1.2.3 From b9bd1681a3b1496c0f1bbe5e6254ab4fd0c9fe30 Mon Sep 17 00:00:00 2001 From: Andy Staudacher Date: Sat, 29 Aug 2009 22:54:20 -0700 Subject: Update all code to use helper method html::clean(), html::purify(), ... instead of SafeString directly. --- modules/comment/controllers/comments.php | 8 ++++---- modules/comment/helpers/comment_rss.php | 8 ++++---- modules/comment/views/admin_block_recent_comments.html.php | 6 +++--- modules/comment/views/admin_comments.html.php | 10 +++++----- modules/comment/views/comment.html.php | 6 +++--- modules/comment/views/comment.mrss.php | 12 ++++++------ modules/comment/views/comments.html.php | 6 +++--- modules/digibug/controllers/digibug.php | 2 +- modules/exif/views/exif_dialog.html.php | 4 ++-- modules/g2_import/helpers/g2_import.php | 2 +- modules/gallery/controllers/admin_advanced_settings.php | 2 +- modules/gallery/controllers/quick.php | 10 +++++----- modules/gallery/helpers/MY_html.php | 4 ++-- modules/gallery/helpers/gallery_rss.php | 4 ++-- modules/gallery/helpers/gallery_task.php | 4 ++-- modules/gallery/tests/Html_Helper_Test.php | 4 ++-- modules/gallery/tests/Xss_Security_Test.php | 4 ++-- modules/gallery/views/admin_advanced_settings.html.php | 6 +++--- modules/gallery/views/admin_block_log_entries.html.php | 2 +- modules/gallery/views/admin_block_photo_stream.html.php | 4 ++-- modules/gallery/views/admin_languages.html.php | 4 ++-- modules/gallery/views/admin_maintenance.html.php | 4 ++-- modules/gallery/views/admin_maintenance_show_log.html.php | 2 +- modules/gallery/views/move_tree.html.php | 8 ++++---- modules/gallery/views/permissions_browse.html.php | 4 ++-- modules/gallery/views/permissions_form.html.php | 2 +- modules/gallery/views/simple_uploader.html.php | 14 +++++++------- modules/info/views/info_block.html.php | 10 +++++----- modules/notification/views/comment_published.html.php | 12 ++++++------ modules/notification/views/item_added.html.php | 8 ++++---- modules/notification/views/item_deleted.html.php | 6 +++--- modules/notification/views/item_updated.html.php | 12 ++++++------ modules/organize/views/organize_dialog.html.php | 2 +- modules/organize/views/organize_tree.html.php | 6 +++--- modules/rss/views/feed.mrss.php | 14 +++++++------- modules/rss/views/rss_block.html.php | 2 +- modules/search/views/search.html.php | 6 +++--- modules/server_add/views/admin_server_add.html.php | 2 +- modules/server_add/views/server_add_tree.html.php | 4 ++-- modules/server_add/views/server_add_tree_dialog.html.php | 6 +++--- modules/tag/controllers/admin_tags.php | 2 +- modules/tag/views/admin_tags.html.php | 6 +++--- modules/tag/views/tag_cloud.html.php | 2 +- modules/user/controllers/logout.php | 2 +- modules/user/views/admin_users.html.php | 8 ++++---- modules/user/views/admin_users_group.html.php | 4 ++-- modules/user/views/login.html.php | 2 +- themes/default/views/album.html.php | 6 +++--- themes/default/views/dynamic.html.php | 4 ++-- themes/default/views/header.html.php | 4 ++-- themes/default/views/movie.html.php | 4 ++-- themes/default/views/photo.html.php | 6 +++--- 52 files changed, 143 insertions(+), 143 deletions(-) diff --git a/modules/comment/controllers/comments.php b/modules/comment/controllers/comments.php index 87633f4c..82b12893 100644 --- a/modules/comment/controllers/comments.php +++ b/modules/comment/controllers/comments.php @@ -39,9 +39,9 @@ class Comments_Controller extends REST_Controller { foreach ($comments as $comment) { $data[] = array( "id" => $comment->id, - "author_name" => SafeString::of($comment->author_name()), + "author_name" => html::clean($comment->author_name()), "created" => $comment->created, - "text" => nl2br(SafeString::purify($comment->text))); + "text" => nl2br(html::purify($comment->text))); } print json_encode($data); break; @@ -126,9 +126,9 @@ class Comments_Controller extends REST_Controller { array("result" => "success", "data" => array( "id" => $comment->id, - "author_name" => SafeString::of($comment->author_name()), + "author_name" => html::clean($comment->author_name()), "created" => $comment->created, - "text" => nl2br(SafeString::purify($comment->text))))); + "text" => nl2br(html::purify($comment->text))))); } else { $view = new Theme_View("comment.html", "fragment"); $view->comment = $comment; diff --git a/modules/comment/helpers/comment_rss.php b/modules/comment/helpers/comment_rss.php index 4151dcd0..b539887b 100644 --- a/modules/comment/helpers/comment_rss.php +++ b/modules/comment/helpers/comment_rss.php @@ -23,7 +23,7 @@ class comment_rss_Core { $feeds["comment/newest"] = t("All new comments"); if ($item) { $feeds["comment/item/$item->id"] = - t("Comments on %title", array("title" => SafeString::purify($item->title))); + t("Comments on %title", array("title" => html::purify($item->title))); } return $feeds; } @@ -49,13 +49,13 @@ class comment_rss_Core { $item = $comment->item(); $feed->children[] = new ArrayObject( array("pub_date" => date("D, d M Y H:i:s T", $comment->created), - "text" => nl2br(SafeString::purify($comment->text)), + "text" => nl2br(html::purify($comment->text)), "thumb_url" => $item->thumb_url(), "thumb_height" => $item->thumb_height, "thumb_width" => $item->thumb_width, "item_uri" => url::abs_site("{$item->type}s/$item->id"), - "title" => SafeString::purify($item->title), - "author" => SafeString::of($comment->author_name())), + "title" => html::purify($item->title), + "author" => html::clean($comment->author_name())), ArrayObject::ARRAY_AS_PROPS); } diff --git a/modules/comment/views/admin_block_recent_comments.html.php b/modules/comment/views/admin_block_recent_comments.html.php index 2c7a5cf1..dc3975e0 100644 --- a/modules/comment/views/admin_block_recent_comments.html.php +++ b/modules/comment/views/admin_block_recent_comments.html.php @@ -4,13 +4,13 @@
                • "> " class="gAvatar" - alt="author_name()) ?>" + alt="author_name()) ?>" width="32" height="32" /> created) ?> %author_name said %comment_text', - array("author_name" => SafeString::of($comment->author_name()), - "comment_text" => text::limit_words(nl2br(SafeString::purify($comment->text)), 50))); ?> + array("author_name" => html::clean($comment->author_name()), + "comment_text" => text::limit_words(nl2br(html::purify($comment->text)), 50))); ?>
                diff --git a/modules/comment/views/admin_comments.html.php b/modules/comment/views/admin_comments.html.php index 8b0b4c29..801ce2b3 100644 --- a/modules/comment/views/admin_comments.html.php +++ b/modules/comment/views/admin_comments.html.php @@ -108,12 +108,12 @@ " class="gAvatar" - alt="author_name()) ?>" + alt="author_name()) ?>" width="40" height="40" /> -

                author_name()) ?>

                +

                author_name()) ?>

              • created) ?>

                - text)) ?> + text)) ?>
                  diff --git a/modules/comment/views/comment.html.php b/modules/comment/views/comment.html.php index 31bb7f4d..1d0786cb 100644 --- a/modules/comment/views/comment.html.php +++ b/modules/comment/views/comment.html.php @@ -4,15 +4,15 @@ " class="gAvatar" - alt="author_name()) ?>" + alt="author_name()) ?>" width="40" height="40" /> gallery::date_time($comment->created), - "author_name" => SafeString::of($comment->author_name()))) ?> + "author_name" => html::clean($comment->author_name()))) ?>

                  - text)) ?> + text)) ?>
                  diff --git a/modules/comment/views/comment.mrss.php b/modules/comment/views/comment.mrss.php index ae7762d9..c2a4b538 100644 --- a/modules/comment/views/comment.mrss.php +++ b/modules/comment/views/comment.mrss.php @@ -6,9 +6,9 @@ xmlns:fh="http://purl.org/syndication/history/1.0"> Gallery 3 - <?= SafeString::of($feed->title) ?> + <?= html::clean($feed->title) ?> uri ?> - description) ?> + description) ?> en-us @@ -22,14 +22,14 @@ children as $child): ?> - <?= SafeString::purify($child->title) ?> - item_uri) ?> - author) ?> + <?= html::purify($child->title) ?> + item_uri) ?> + author) ?> item_uri ?> pub_date ?> text)) ?>

                  +

                  text)) ?>

                  diff --git a/modules/comment/views/comments.html.php b/modules/comment/views/comments.html.php index 9eac0502..1e45c946 100644 --- a/modules/comment/views/comments.html.php +++ b/modules/comment/views/comments.html.php @@ -18,16 +18,16 @@ " class="gAvatar" - alt="author_name()) ?>" + alt="author_name()) ?>" width="40" height="40" /> %name said', array("date" => date("Y-M-d H:i:s", $comment->created), - "name" => SafeString::of($comment->author_name()))); ?> + "name" => html::clean($comment->author_name()))); ?>

                  - text)) ?> + text)) ?>
                  diff --git a/modules/digibug/controllers/digibug.php b/modules/digibug/controllers/digibug.php index 509a8b70..0939704b 100644 --- a/modules/digibug/controllers/digibug.php +++ b/modules/digibug/controllers/digibug.php @@ -50,7 +50,7 @@ class Digibug_Controller extends Controller { "image_width_1" => $item->width, "thumb_height_1" => $item->thumb_height, "thumb_width_1" => $item->thumb_width, - "title_1" => SafeString::purify($item->title)); + "title_1" => html::purify($item->title)); print $v; } diff --git a/modules/exif/views/exif_dialog.html.php b/modules/exif/views/exif_dialog.html.php index a981ca09..11d1e212 100644 --- a/modules/exif/views/exif_dialog.html.php +++ b/modules/exif/views/exif_dialog.html.php @@ -14,14 +14,14 @@ - + - + diff --git a/modules/g2_import/helpers/g2_import.php b/modules/g2_import/helpers/g2_import.php index a01ca1db..7e5c6f75 100644 --- a/modules/g2_import/helpers/g2_import.php +++ b/modules/g2_import/helpers/g2_import.php @@ -590,7 +590,7 @@ class g2_import_Core { self::map($g2_comment->getId(), $comment->id); return t("Imported comment '%comment' for item with id: %id", array("id" => $comment->item_id, - "comment" => text::limit_words(nl2br(SafeString::purify($comment->text)), 50))); + "comment" => text::limit_words(nl2br(html::purify($comment->text)), 50))); } /** diff --git a/modules/gallery/controllers/admin_advanced_settings.php b/modules/gallery/controllers/admin_advanced_settings.php index d727b654..43c77340 100644 --- a/modules/gallery/controllers/admin_advanced_settings.php +++ b/modules/gallery/controllers/admin_advanced_settings.php @@ -46,7 +46,7 @@ class Admin_Advanced_Settings_Controller extends Admin_Controller { module::set_var($module_name, $var_name, Input::instance()->post("value")); message::success( t("Saved value for %var (%module_name)", - array("var" => SafeString::of($var_name), "module_name" => $module_name))); + array("var" => html::clean($var_name), "module_name" => $module_name))); print json_encode(array("result" => "success")); } diff --git a/modules/gallery/controllers/quick.php b/modules/gallery/controllers/quick.php index 8fddb563..20731f9c 100644 --- a/modules/gallery/controllers/quick.php +++ b/modules/gallery/controllers/quick.php @@ -75,7 +75,7 @@ class Quick_Controller extends Controller { access::required("view", $item->parent()); access::required("edit", $item->parent()); - $msg = t("Made %title this album's cover", array("title" => SafeString::purify($item->title))); + $msg = t("Made %title this album's cover", array("title" => html::purify($item->title))); item::make_album_cover($item); message::success($msg); @@ -91,10 +91,10 @@ class Quick_Controller extends Controller { if ($item->is_album()) { print t( "Delete the album %title? All photos and movies in the album will also be deleted.", - array("title" => SafeString::purify($item->title))); + array("title" => html::purify($item->title))); } else { print t("Are you sure you want to delete %title?", - array("title" => SafeString::purify($item->title))); + array("title" => html::purify($item->title))); } $form = item::get_delete_form($item); @@ -108,9 +108,9 @@ class Quick_Controller extends Controller { access::required("edit", $item); if ($item->is_album()) { - $msg = t("Deleted album %title", array("title" => SafeString::purify($item->title))); + $msg = t("Deleted album %title", array("title" => html::purify($item->title))); } else { - $msg = t("Deleted photo %title", array("title" => SafeString::purify($item->title))); + $msg = t("Deleted photo %title", array("title" => html::purify($item->title))); } $parent = $item->parent(); diff --git a/modules/gallery/helpers/MY_html.php b/modules/gallery/helpers/MY_html.php index eb388811..75114898 100644 --- a/modules/gallery/helpers/MY_html.php +++ b/modules/gallery/helpers/MY_html.php @@ -65,11 +65,11 @@ class html extends html_Core { * * Example:
                      *   
                   
                  -

                  SafeString::purify($album->title))) ?>

                  +

                  html::purify($album->title))) ?>

                  diff --git a/modules/organize/views/organize_tree.html.php b/modules/organize/views/organize_tree.html.php index 387d5977..5b676889 100644 --- a/modules/organize/views/organize_tree.html.php +++ b/modules/organize/views/organize_tree.html.php @@ -5,7 +5,7 @@ - title) ?> + title) ?>
                    @@ -17,7 +17,7 @@ " ref="id ?>"> - title) ?> + title) ?> id == $album->id): ?> @@ -29,7 +29,7 @@ - title) ?> + title) ?> diff --git a/modules/rss/views/feed.mrss.php b/modules/rss/views/feed.mrss.php index 7298b7f4..731703c7 100644 --- a/modules/rss/views/feed.mrss.php +++ b/modules/rss/views/feed.mrss.php @@ -6,9 +6,9 @@ xmlns:fh="http://purl.org/syndication/history/1.0"> gallery3 - <?= SafeString::of($feed->title) ?> + <?= html::clean($feed->title) ?> uri ?> - description) ?> + description) ?> en-us @@ -22,25 +22,25 @@ children as $child): ?> - <?= SafeString::of($child->title) ?> + <?= html::clean($child->title) ?> type}s/{$child->id}") ?> type}s/{$child->id}") ?> created); ?> description) ?> + description) ?>

                    type == "photo" || $child->type == "album"): ?>
                    type}s/{$child->id}") ?>">
                    - description) ?> + description) ?>

                    ]]>
                    diff --git a/modules/rss/views/rss_block.html.php b/modules/rss/views/rss_block.html.php index cd8db89d..737731b6 100644 --- a/modules/rss/views/rss_block.html.php +++ b/modules/rss/views/rss_block.html.php @@ -5,7 +5,7 @@ - + diff --git a/modules/search/views/search.html.php b/modules/search/views/search.html.php index e5c7b4a6..7963948d 100644 --- a/modules/search/views/search.html.php +++ b/modules/search/views/search.html.php @@ -8,7 +8,7 @@
                    • - +
                    • for_html_attr() ?>" /> @@ -31,10 +31,10 @@ id") ?>"> thumb_img() ?>

                      - title) ?> + title) ?>

                      - description)) ?> + description)) ?>
                    • diff --git a/modules/server_add/views/admin_server_add.html.php b/modules/server_add/views/admin_server_add.html.php index c4439bda..b48a19da 100644 --- a/modules/server_add/views/admin_server_add.html.php +++ b/modules/server_add/views/admin_server_add.html.php @@ -16,7 +16,7 @@ class="gRemoveDir ui-icon ui-icon-trash"> X - +
                    diff --git a/modules/server_add/views/server_add_tree.html.php b/modules/server_add/views/server_add_tree.html.php index 2f65a590..dbae42c5 100644 --- a/modules/server_add/views/server_add_tree.html.php +++ b/modules/server_add/views/server_add_tree.html.php @@ -10,7 +10,7 @@
                  • - +
                      @@ -24,7 +24,7 @@ file=" '\\"')) ?>" > - + diff --git a/modules/server_add/views/server_add_tree_dialog.html.php b/modules/server_add/views/server_add_tree_dialog.html.php index 912e69b6..8eb6e4df 100644 --- a/modules/server_add/views/server_add_tree_dialog.html.php +++ b/modules/server_add/views/server_add_tree_dialog.html.php @@ -5,17 +5,17 @@
                      -

                      SafeString::purify($item->title))) ?>

                      +

                      html::purify($item->title))) ?>

                        parents() as $parent): ?>
                      • - title) ?> + title) ?>
                      • - title) ?> + title) ?>
                      diff --git a/modules/tag/controllers/admin_tags.php b/modules/tag/controllers/admin_tags.php index f1b4ca3a..8b8dde21 100644 --- a/modules/tag/controllers/admin_tags.php +++ b/modules/tag/controllers/admin_tags.php @@ -106,7 +106,7 @@ class Admin_Tags_Controller extends Admin_Controller { array("result" => "success", "location" => url::site("admin/tags"), "tag_id" => $tag->id, - "new_tagname" => SafeString::of($tag->name))); + "new_tagname" => html::clean($tag->name))); } else { print json_encode( array("result" => "error", diff --git a/modules/tag/views/admin_tags.html.php b/modules/tag/views/admin_tags.html.php index 30dd0728..3d805c5e 100644 --- a/modules/tag/views/admin_tags.html.php +++ b/modules/tag/views/admin_tags.html.php @@ -32,7 +32,7 @@ name, 0, 1)) ?> - +
                        $tags_per_column): /* new column */ ?> @@ -42,12 +42,12 @@
                      - + diff --git a/modules/user/controllers/logout.php b/modules/user/controllers/logout.php index 4b141a1c..fc3ced56 100644 --- a/modules/user/controllers/logout.php +++ b/modules/user/controllers/logout.php @@ -24,7 +24,7 @@ class Logout_Controller extends Controller { $user = user::active(); user::logout(); log::info("user", t("User %name logged out", array("name" => $user->name)), - html::anchor("user/$user->id", SafeString::of($user->name))); + html::anchor("user/$user->id", html::clean($user->name))); if ($continue_url = $this->input->get("continue")) { $item = url::get_item_from_uri($continue_url); if (access::can("view", $item)) { diff --git a/modules/user/views/admin_users.html.php b/modules/user/views/admin_users.html.php index 36c4f4fd..9455f9d9 100644 --- a/modules/user/views/admin_users.html.php +++ b/modules/user/views/admin_users.html.php @@ -68,16 +68,16 @@ " title="" - alt="name) ?>" + alt="name) ?>" width="20" height="20" /> - name) ?> + name) ?> - full_name) ?> + full_name) ?> - email) ?> + email) ?> last_login == 0) ? "" : gallery::date($user->last_login) ?> diff --git a/modules/user/views/admin_users_group.html.php b/modules/user/views/admin_users_group.html.php index f89a4392..8418ebc9 100644 --- a/modules/user/views/admin_users_group.html.php +++ b/modules/user/views/admin_users_group.html.php @@ -1,6 +1,6 @@

                      - name) ?> + name) ?> special): ?> id") ?>" title=" $group->name)) ?>" @@ -17,7 +17,7 @@

                        @@ -16,7 +16,7 @@ width="thumb_width ?>" height="thumb_height ?>" /> -

                        title) ?>

                        +

                        title) ?>

                        thumb_bottom($child) ?> diff --git a/themes/default/views/movie.html.php b/themes/default/views/movie.html.php index 237743b7..910814dd 100644 --- a/themes/default/views/movie.html.php +++ b/themes/default/views/movie.html.php @@ -28,8 +28,8 @@ movie_img(array("class" => "gMovie", "id" => "gMovieId-{$item->id}")) ?>
                        -

                        title) ?>

                        -
                        description)) ?>
                        +

                        title) ?>

                        +
                        description)) ?>
                        photo_bottom() ?> diff --git a/themes/default/views/photo.html.php b/themes/default/views/photo.html.php index 5b5cb12b..c601c4cc 100644 --- a/themes/default/views/photo.html.php +++ b/themes/default/views/photo.html.php @@ -5,7 +5,7 @@ *
                  */ - static function clean_js($string) { + static function js_string($string) { return SafeString::of($string)->for_js(); } diff --git a/modules/gallery/libraries/SafeString.php b/modules/gallery/libraries/SafeString.php index 9614a213..0767a665 100644 --- a/modules/gallery/libraries/SafeString.php +++ b/modules/gallery/libraries/SafeString.php @@ -92,17 +92,17 @@ class SafeString_Core { } /** - * Safe for use in JavaScript. + * Safe for use as JavaScript string. * * Example:
                      *   
                      * 
                  * @return the string escaped for use in JavaScript. */ function for_js() { - return self::_escape_for_js($this->_raw_string); + return json_encode((string) $this->_raw_string); } /** @@ -152,14 +152,6 @@ class SafeString_Core { return html::specialchars($dirty_html); } - // Escapes special chars (quotes, backslash, etc.) with a backslash sequence. - private static function _escape_for_js($string) { - // From Smarty plugins/modifier.escape.php - // Might want to be stricter here. - return strtr($string, - array('\\'=>'\\\\',"'"=>"\\'",'"'=>'\\"',"\r"=>'\\r',"\n"=>'\\n',''<\/')); - } - // Purifies the string, removing any potentially malicious or unsafe HTML / JavaScript. private static function _purify_for_html($dirty_html) { if (empty(self::$_purifier)) { diff --git a/modules/gallery/tests/Html_Helper_Test.php b/modules/gallery/tests/Html_Helper_Test.php index a9903256..f5ce7fa4 100644 --- a/modules/gallery/tests/Html_Helper_Test.php +++ b/modules/gallery/tests/Html_Helper_Test.php @@ -40,9 +40,9 @@ class Html_Helper_Test extends Unit_Test_Case { $safe_string_2); } - public function clean_js_test() { - $string = html::clean_js("hello's

                  world

                  "); - $this->assert_equal("hello\\'s

                  world<\\/p>", + public function js_string_test() { + $string = html::js_string("hello's

                  world

                  "); + $this->assert_equal('"hello\'s

                  world<\\/p>"', $string); } diff --git a/modules/gallery/tests/SafeString_Test.php b/modules/gallery/tests/SafeString_Test.php index 0fc7f6f3..ede55240 100644 --- a/modules/gallery/tests/SafeString_Test.php +++ b/modules/gallery/tests/SafeString_Test.php @@ -49,7 +49,7 @@ class SafeString_Test extends Unit_Test_Case { public function for_js_test() { $safe_string = new SafeString('"Foo\'s bar"'); $js_string = $safe_string->for_js(); - $this->assert_equal('\\"Foo<\\/em>\\\'s bar\\"', + $this->assert_equal('"\\"Foo<\\/em>\'s bar\\""', $js_string); } @@ -96,21 +96,21 @@ class SafeString_Test extends Unit_Test_Case { public function of_fluid_api_test() { $escaped_string = SafeString::of("Foo's bar")->for_js(); - $this->assert_equal("Foo\\'s bar", $escaped_string); + $this->assert_equal('"Foo\'s bar"', $escaped_string); } public function safestring_of_safestring_preserves_safe_status_test() { $safe_string = SafeString::of_safe_html("hello's

                  world

                  "); $safe_string_2 = new SafeString($safe_string); $this->assert_equal("hello's

                  world

                  ", $safe_string_2); - $this->assert_equal("hello\\'s

                  world<\\/p>", $safe_string_2->for_js()); + $this->assert_equal('"hello\'s

                  world<\\/p>"', $safe_string_2->for_js()); } public function safestring_of_safestring_preserves_html_safe_status_test() { $safe_string = SafeString::of_safe_html("hello's

                  world

                  "); $safe_string_2 = new SafeString($safe_string); $this->assert_equal("hello's

                  world

                  ", $safe_string_2); - $this->assert_equal("hello\\'s

                  world<\\/p>", $safe_string_2->for_js()); + $this->assert_equal('"hello\'s

                  world<\\/p>"', $safe_string_2->for_js()); } public function safestring_of_safestring_safe_status_override_test() { diff --git a/modules/gallery/tests/Xss_Security_Test.php b/modules/gallery/tests/Xss_Security_Test.php index b385580d..3a22afc1 100644 --- a/modules/gallery/tests/Xss_Security_Test.php +++ b/modules/gallery/tests/Xss_Security_Test.php @@ -188,7 +188,7 @@ class Xss_Security_Test extends Unit_Test_Case { if (self::_token_matches(array(T_DOUBLE_COLON, "::"), $tokens, $token_number + 1) && self::_token_matches(array(T_STRING), $tokens, $token_number + 2) && in_array($tokens[$token_number + 2][1], - array("clean", "purify", "clean_js", "clean_attribute")) && + array("clean", "purify", "js_string", "clean_attribute")) && self::_token_matches("(", $tokens, $token_number + 3)) { // Not checking for mark_safe(). We want such calls to be marked dirty (thus reviewed). @@ -198,7 +198,7 @@ class Xss_Security_Test extends Unit_Test_Case { $token_number += 3; $token = $tokens[$token_number]; - if ("clean_js" == $method) { + if ("js_string" == $method) { $frame->is_safe_js(true); } else { $frame->is_safe_html(true); -- cgit v1.2.3 From 00c73ec852c29c214d72193ce368bc12a7305794 Mon Sep 17 00:00:00 2001 From: Andy Staudacher Date: Sun, 30 Aug 2009 15:34:46 -0700 Subject: Updating uses of html::js_string and SafeString::for_js (value now contains string delimiters) --- modules/gallery/views/admin_languages.html.php | 86 +++++++++++------------ modules/gallery/views/l10n_client.html.php | 10 +-- modules/gallery/views/permissions_browse.html.php | 17 ++--- modules/gallery/views/simple_uploader.html.php | 50 ++++++------- themes/admin_default/views/admin.html.php | 2 +- themes/default/views/page.html.php | 4 +- themes/default/views/photo.html.php | 2 +- 7 files changed, 85 insertions(+), 86 deletions(-) diff --git a/modules/gallery/views/admin_languages.html.php b/modules/gallery/views/admin_languages.html.php index ae2b3383..fa97d299 100644 --- a/modules/gallery/views/admin_languages.html.php +++ b/modules/gallery/views/admin_languages.html.php @@ -11,12 +11,11 @@ - + $display_name): ?> - - + @@ -24,24 +23,24 @@ - + "> - - + + - +
                  - - + +
                  - for_html_attr() ?>" /> + for_html_attr() ?>" /> - - diff --git a/modules/gallery/views/permissions_browse.html.php b/modules/gallery/views/permissions_browse.html.php index d9395b3f..231daa04 100644 --- a/modules/gallery/views/permissions_browse.html.php +++ b/modules/gallery/views/permissions_browse.html.php @@ -5,9 +5,9 @@ $.ajax({ url: form_url.replace("__ITEM__", id), success: function(data) { - $("#gEditPermissionForm").html(data); - $(".active").removeClass("active"); - $("#item-" + id).addClass("active"); + $("#gEditPermissionForm").html(data); + $(".active").removeClass("active"); + $("#item-" + id).addClass("active"); } }); } @@ -28,13 +28,14 @@

                  • - mod_rewrite and set AllowOverride FileInfo Options to fix this.", array("mod_rewrite_attrs" => "href=\"http://httpd.apache.org/docs/2.0/mod/mod_rewrite.html\" target=\"_blank\"", "apache_attrs" => "href=\"http://httpd.apache.org/docs/2.0/mod/core.html#allowoverride\" target=\"_blank\"")) ?> + mod_rewrite and set AllowOverride FileInfo Options to fix this.", + array("mod_rewrite_attrs" => html::mark_safe("href=\"http://httpd.apache.org/docs/2.0/mod/mod_rewrite.html\" target=\"_blank\"", "apache_attrs" => "href=\"http://httpd.apache.org/docs/2.0/mod/core.html#allowoverride\" target=\"_blank\""))) ?>
                  - +

                  - + - +
                  diff --git a/modules/gallery/views/simple_uploader.html.php b/modules/gallery/views/simple_uploader.html.php index ccb166fc..9cf554ec 100644 --- a/modules/gallery/views/simple_uploader.html.php +++ b/modules/gallery/views/simple_uploader.html.php @@ -82,22 +82,22 @@ diff --git a/themes/admin_default/views/admin.html.php b/themes/admin_default/views/admin.html.php index 2ed8c38e..3b1ff92c 100644 --- a/themes/admin_default/views/admin.html.php +++ b/themes/admin_default/views/admin.html.php @@ -23,7 +23,7 @@ script("gallery.common.js") ?> script("gallery.ajax.js") ?> script("gallery.dialog.js") ?> diff --git a/themes/default/views/page.html.php b/themes/default/views/page.html.php index 844ef295..2696442b 100644 --- a/themes/default/views/page.html.php +++ b/themes/default/views/page.html.php @@ -12,7 +12,7 @@ item()->is_album()): ?> $theme->item()->title)) ?> item()->is_photo()): ?> - $theme->item()->title)) ?> + $theme->item()->title)) ?> $theme->item()->title)) ?> @@ -51,7 +51,7 @@ script("gallery.common.js") ?> script("gallery.ajax.js") ?> script("gallery.dialog.js") ?> diff --git a/themes/default/views/photo.html.php b/themes/default/views/photo.html.php index 00e157ce..5289b467 100644 --- a/themes/default/views/photo.html.php +++ b/themes/default/views/photo.html.php @@ -5,7 +5,7 @@ block? - if (is_array($token) && $token[0] == T_INLINE_HTML) { - $inline_html = $token[1]; - // T_INLINE_HTML blocks can be split. Need to handle the case - // where one token has "expr_append($inline_html); - } - - // Note: This approach won't catch }i', $inline_html, $matches, PREG_OFFSET_CAPTURE)) { - $last_match = array_pop($matches[0]); - if (is_array($last_match)) { - $closing_script_pos = $last_match[1]; - } else { - $closing_script_pos = $last_match; - } - } - if (preg_match('{]*>}i', $inline_html, $matches, PREG_OFFSET_CAPTURE)) { - $last_match = array_pop($matches[0]); - if (is_array($last_match)) { - $opening_script_pos = $last_match[1]; - } else { - $opening_script_pos = $last_match; - } - } - if ($opening_script_pos != $closing_script_pos) { - $in_script_block = $opening_script_pos > $closing_script_pos; - } - } - - // Look and report each instance of < ? = ... ? > - if (!is_array($token)) { - // A single char token, e.g: ; ( ) - if ($frame) { - $frame->expr_append($token); - } - } else if ($token[0] == T_OPEN_TAG_WITH_ECHO) { - // No need for a stack here - assume < ? = cannot be nested. - $frame = self::_create_frame($token, $in_script_block); + $token = $tokens[$token_number]; + + // Are we in a block? + if (is_array($token) && $token[0] == T_INLINE_HTML) { + $inline_html = $token[1]; + // T_INLINE_HTML blocks can be split. Need to handle the case + // where one token has "expr_append($inline_html); + } + + // Note: This approach won't catch }i', $inline_html, $matches, PREG_OFFSET_CAPTURE)) { + $last_match = array_pop($matches[0]); + if (is_array($last_match)) { + $closing_script_pos = $last_match[1]; + } else { + $closing_script_pos = $last_match; + } + } + if (preg_match('{]*>}i', $inline_html, $matches, PREG_OFFSET_CAPTURE)) { + $last_match = array_pop($matches[0]); + if (is_array($last_match)) { + $opening_script_pos = $last_match[1]; + } else { + $opening_script_pos = $last_match; + } + } + if ($opening_script_pos != $closing_script_pos) { + $in_script_block = $opening_script_pos > $closing_script_pos; + } + } + + // Look and report each instance of < ? = ... ? > + if (!is_array($token)) { + // A single char token, e.g: ; ( ) + if ($frame) { + $frame->expr_append($token); + } + } else if ($token[0] == T_OPEN_TAG_WITH_ECHO) { + // No need for a stack here - assume < ? = cannot be nested. + $frame = self::_create_frame($token, $in_script_block); } else if ($frame && $token[0] == T_CLOSE_TAG) { - // Store the < ? = ... ? > block that just ended here. - $found[$view][] = $frame; - $frame = null; + // Store the < ? = ... ? > block that just ended here. + $found[$view][] = $frame; + $frame = null; } else if ($frame && $token[0] == T_VARIABLE) { - $frame->expr_append($token[1]); + $frame->expr_append($token[1]); if ($token[1] == '$theme') { - if (self::_token_matches(array(T_OBJECT_OPERATOR, "->"), $tokens, $token_number + 1) && - self::_token_matches(array(T_STRING), $tokens, $token_number + 2) && - in_array($tokens[$token_number + 2][1], - array("thumb_proportion", "site_menu", "album_menu", "tag_menu", "photo_menu", + if (self::_token_matches(array(T_OBJECT_OPERATOR, "->"), $tokens, $token_number + 1) && + self::_token_matches(array(T_STRING), $tokens, $token_number + 2) && + in_array($tokens[$token_number + 2][1], + array("thumb_proportion", "site_menu", "album_menu", "tag_menu", "photo_menu", "context_menu", "pager", "site_status", "messages", "album_blocks", "album_bottom", "album_top", "body_attributes", "credits", "dynamic_bottom", "dynamic_top", "footer", "head", "header_bottom", "header_top", "page_bottom", "page_top", "photo_blocks", "photo_bottom", "photo_top", "resize_bottom", "resize_top", "sidebar_blocks", "sidebar_bottom", "sidebar_top", "thumb_bottom", "thumb_info", "thumb_top")) && - self::_token_matches("(", $tokens, $token_number + 3)) { + self::_token_matches("(", $tokens, $token_number + 3)) { - $method = $tokens[$token_number + 2][1]; - $frame->expr_append("->$method("); + $method = $tokens[$token_number + 2][1]; + $frame->expr_append("->$method("); - $token_number += 3; - $token = $tokens[$token_number]; + $token_number += 3; + $token = $tokens[$token_number]; $frame->is_safe_html(true); - } else if (self::_token_matches(array(T_OBJECT_OPERATOR, "->"), $tokens, $token_number + 1) && - self::_token_matches(array(T_STRING), $tokens, $token_number + 2) && - in_array($tokens[$token_number + 2][1], - array("css", "script", "url")) && - self::_token_matches("(", $tokens, $token_number + 3) && - // Only allow constant strings here - self::_token_matches(array(T_CONSTANT_ENCAPSED_STRING), $tokens, $token_number + 4)) { + } else if (self::_token_matches(array(T_OBJECT_OPERATOR, "->"), $tokens, $token_number + 1) && + self::_token_matches(array(T_STRING), $tokens, $token_number + 2) && + in_array($tokens[$token_number + 2][1], + array("css", "script", "url")) && + self::_token_matches("(", $tokens, $token_number + 3) && + // Only allow constant strings here + self::_token_matches(array(T_CONSTANT_ENCAPSED_STRING), $tokens, $token_number + 4)) { - $method = $tokens[$token_number + 2][1]; - $frame->expr_append("->$method("); + $method = $tokens[$token_number + 2][1]; + $frame->expr_append("->$method("); - $token_number += 4; - $token = $tokens[$token_number]; + $token_number += 4; + $token = $tokens[$token_number]; $frame->is_safe_html(true); - } + } } - } else if ($frame && $token[0] == T_STRING) { - $frame->expr_append($token[1]); - // t() and t2() are special in that they're guaranteed to return a SafeString(). - if (in_array($token[1], array("t", "t2"))) { - if (self::_token_matches("(", $tokens, $token_number + 1)) { - $frame->is_safe_html(true); - $frame->expr_append("("); - - $token_number++; - $token = $tokens[$token_number]; - } - } else if ($token[1] == "SafeString") { - // Looking for SafeString::of(... - if (self::_token_matches(array(T_DOUBLE_COLON, "::"), $tokens, $token_number + 1) && - self::_token_matches(array(T_STRING), $tokens, $token_number + 2) && - in_array($tokens[$token_number + 2][1], array("of", "purify")) && - self::_token_matches("(", $tokens, $token_number + 3)) { + } else if ($frame && $token[0] == T_STRING) { + $frame->expr_append($token[1]); + // t() and t2() are special in that they're guaranteed to return a SafeString(). + if (in_array($token[1], array("t", "t2"))) { + if (self::_token_matches("(", $tokens, $token_number + 1)) { + $frame->is_safe_html(true); + $frame->expr_append("("); + + $token_number++; + $token = $tokens[$token_number]; + } + } else if ($token[1] == "SafeString") { + // Looking for SafeString::of(... + if (self::_token_matches(array(T_DOUBLE_COLON, "::"), $tokens, $token_number + 1) && + self::_token_matches(array(T_STRING), $tokens, $token_number + 2) && + in_array($tokens[$token_number + 2][1], array("of", "purify")) && + self::_token_matches("(", $tokens, $token_number + 3)) { // Not checking for of_safe_html(). We want such calls to be marked dirty (thus reviewed). - $frame->is_safe_html(true); - - $method = $tokens[$token_number + 2][1]; - $frame->expr_append("::$method("); - - $token_number += 3; - $token = $tokens[$token_number]; - } - } else if ($token[1] == "json_encode") { - if (self::_token_matches("(", $tokens, $token_number + 1)) { - $frame->is_safe_js(true); - $frame->expr_append("("); - - $token_number++; - $token = $tokens[$token_number]; - } - } else if ($token[1] == "url") { - // url methods return safe HTML - if (self::_token_matches(array(T_DOUBLE_COLON, "::"), $tokens, $token_number + 1) && - self::_token_matches(array(T_STRING), $tokens, $token_number + 2) && - in_array($tokens[$token_number + 2][1], - array("site", "current", "base", "file", "abs_site", "abs_current", - "abs_file", "merge")) && - self::_token_matches("(", $tokens, $token_number + 3)) { - $frame->is_safe_html(true); - - $method = $tokens[$token_number + 2][1]; - $frame->expr_append("::$method("); - - $token_number += 3; - $token = $tokens[$token_number]; - } - } else if ($token[1] == "html") { - if (self::_token_matches(array(T_DOUBLE_COLON, "::"), $tokens, $token_number + 1) && - self::_token_matches(array(T_STRING), $tokens, $token_number + 2) && - in_array($tokens[$token_number + 2][1], - array("clean", "purify", "js_string", "clean_attribute")) && - self::_token_matches("(", $tokens, $token_number + 3)) { + $frame->is_safe_html(true); + + $method = $tokens[$token_number + 2][1]; + $frame->expr_append("::$method("); + + $token_number += 3; + $token = $tokens[$token_number]; + } + } else if ($token[1] == "json_encode") { + if (self::_token_matches("(", $tokens, $token_number + 1)) { + $frame->is_safe_js(true); + $frame->expr_append("("); + + $token_number++; + $token = $tokens[$token_number]; + } + } else if ($token[1] == "url") { + // url methods return safe HTML + if (self::_token_matches(array(T_DOUBLE_COLON, "::"), $tokens, $token_number + 1) && + self::_token_matches(array(T_STRING), $tokens, $token_number + 2) && + in_array($tokens[$token_number + 2][1], + array("site", "current", "base", "file", "abs_site", "abs_current", + "abs_file", "merge")) && + self::_token_matches("(", $tokens, $token_number + 3)) { + $frame->is_safe_html(true); + + $method = $tokens[$token_number + 2][1]; + $frame->expr_append("::$method("); + + $token_number += 3; + $token = $tokens[$token_number]; + } + } else if ($token[1] == "html") { + if (self::_token_matches(array(T_DOUBLE_COLON, "::"), $tokens, $token_number + 1) && + self::_token_matches(array(T_STRING), $tokens, $token_number + 2) && + in_array($tokens[$token_number + 2][1], + array("clean", "purify", "js_string", "clean_attribute")) && + self::_token_matches("(", $tokens, $token_number + 3)) { // Not checking for mark_safe(). We want such calls to be marked dirty (thus reviewed). - $method = $tokens[$token_number + 2][1]; - $frame->expr_append("::$method("); + $method = $tokens[$token_number + 2][1]; + $frame->expr_append("::$method("); - $token_number += 3; - $token = $tokens[$token_number]; + $token_number += 3; + $token = $tokens[$token_number]; if ("js_string" == $method) { $frame->is_safe_js(true); } else { $frame->is_safe_html(true); } - } - } - } else if ($frame && $token[0] == T_OBJECT_OPERATOR) { - $frame->expr_append($token[1]); - - if (self::_token_matches(array(T_STRING), $tokens, $token_number + 1) && - in_array($tokens[$token_number + 1][1], - array("for_js", "for_html", "purified_html", "for_html_attr")) && - self::_token_matches("(", $tokens, $token_number + 2)) { - $method = $tokens[$token_number + 1][1]; - $frame->expr_append("$method("); - - $token_number += 2; - $token = $tokens[$token_number]; - - if ("for_js" == $method) { - $frame->is_safe_js(true); - } else { - $frame->is_safe_html(true); - } - } + } + } + } else if ($frame && $token[0] == T_OBJECT_OPERATOR) { + $frame->expr_append($token[1]); + + if (self::_token_matches(array(T_STRING), $tokens, $token_number + 1) && + in_array($tokens[$token_number + 1][1], + array("for_js", "for_html", "purified_html", "for_html_attr")) && + self::_token_matches("(", $tokens, $token_number + 2)) { + $method = $tokens[$token_number + 1][1]; + $frame->expr_append("$method("); + + $token_number += 2; + $token = $tokens[$token_number]; + + if ("for_js" == $method) { + $frame->is_safe_js(true); + } else { + $frame->is_safe_html(true); + } + } } else if ($frame) { - $frame->expr_append($token[1]); - } + $frame->expr_append($token[1]); + } } } @@ -252,26 +252,26 @@ class Xss_Security_Test extends Unit_Test_Case { ksort($found); foreach ($found as $view => $frames) { foreach ($frames as $frame) { - $state = "DIRTY"; - if ($frame->in_script_block()) { - $state = "DIRTY_JS"; - if ($frame->is_safe_js()) { - $state = "CLEAN"; - } - } else { - if ($frame->is_safe_html()) { - $state = "CLEAN"; - } - } - - if ("CLEAN" == $state) { - // Don't print CLEAN instances - No need to update the golden - // file when adding / moving clean instances. - continue; - } - - fprintf($fd, "%-60s %-3s %-8s %s\n", - $view, $frame->line(), $state, $frame->expr()); + $state = "DIRTY"; + if ($frame->in_script_block()) { + $state = "DIRTY_JS"; + if ($frame->is_safe_js()) { + $state = "CLEAN"; + } + } else { + if ($frame->is_safe_html()) { + $state = "CLEAN"; + } + } + + if ("CLEAN" == $state) { + // Don't print CLEAN instances - No need to update the golden + // file when adding / moving clean instances. + continue; + } + + fprintf($fd, "%-60s %-3s %-8s %s\n", + $view, $frame->line(), $state, $frame->expr()); } } fclose($fd); @@ -280,7 +280,7 @@ class Xss_Security_Test extends Unit_Test_Case { $canonical = MODPATH . "gallery/tests/xss_data.txt"; exec("diff $canonical $new", $output, $return_value); $this->assert_false( - $return_value, "XSS golden file mismatch. Output:\n" . implode("\n", $output) ); + $return_value, "XSS golden file mismatch. Output:\n" . implode("\n", $output) ); } private static function _create_frame($token, $in_script_block) { @@ -296,9 +296,9 @@ class Xss_Security_Test extends Unit_Test_Case { if (is_array($expected_token)) { for ($i = 0; $i < count($expected_token); $i++) { - if ($expected_token[$i] != $token[$i]) { - return false; - } + if ($expected_token[$i] != $token[$i]) { + return false; + } } return true; } else { diff --git a/modules/server_add/helpers/server_add_event.php b/modules/server_add/helpers/server_add_event.php index 6b21ec2e..b2d55153 100644 --- a/modules/server_add/helpers/server_add_event.php +++ b/modules/server_add/helpers/server_add_event.php @@ -35,7 +35,7 @@ class server_add_event_Core { // turn that into a dropdown if there are two different ways to add things. Do that in a // portable way for now. If we find ourselves duplicating this pattern, we should make an // API method for this. - $add_menu = $menu->get("add_menu"); + $add_menu = $menu->get("add_menu"); $add_menu->append(Menu::factory("dialog") ->id("server_add") ->label(t("Server add")) -- cgit v1.2.3 From 3aef420d485871ed95be742bae0d971e637e4a75 Mon Sep 17 00:00:00 2001 From: Andy Staudacher Date: Sun, 30 Aug 2009 18:37:01 -0700 Subject: Updating XSS golden file --- modules/gallery/tests/xss_data.txt | 73 ++++++++++++++++++-------------------- 1 file changed, 35 insertions(+), 38 deletions(-) diff --git a/modules/gallery/tests/xss_data.txt b/modules/gallery/tests/xss_data.txt index de37d11e..5b43d1e5 100644 --- a/modules/gallery/tests/xss_data.txt +++ b/modules/gallery/tests/xss_data.txt @@ -61,12 +61,12 @@ modules/gallery/views/admin_graphics_imagemagick.html.php 2 DIRTY $is_ac modules/gallery/views/admin_graphics_imagemagick.html.php 2 DIRTY $tk->installed?" gInstalledToolkit":" gUnavailable" modules/gallery/views/admin_graphics_imagemagick.html.php 18 DIRTY $tk->error modules/gallery/views/admin_languages.html.php 9 DIRTY access::csrf_form_field() -modules/gallery/views/admin_languages.html.php 28 DIRTY (isset($installed_locales[$code]))?"installed":"" -modules/gallery/views/admin_languages.html.php 28 DIRTY ($default_locale==$code)?" default":"" -modules/gallery/views/admin_languages.html.php 29 DIRTY form::checkbox("installed_locales[]",$code,isset($installed_locales[$code])) -modules/gallery/views/admin_languages.html.php 30 DIRTY $display_name -modules/gallery/views/admin_languages.html.php 32 DIRTY form::radio("default_locale",$code,($default_locale==$code),((isset($installed_locales[$code]))?'':'disabled="disabled"')) -modules/gallery/views/admin_languages.html.php 104 DIRTY $share_translations_form +modules/gallery/views/admin_languages.html.php 27 DIRTY (isset($installed_locales[$code]))?"installed":"" +modules/gallery/views/admin_languages.html.php 27 DIRTY ($default_locale==$code)?" default":"" +modules/gallery/views/admin_languages.html.php 28 DIRTY form::checkbox("installed_locales[]",$code,isset($installed_locales[$code])) +modules/gallery/views/admin_languages.html.php 29 DIRTY $display_name +modules/gallery/views/admin_languages.html.php 31 DIRTY form::radio("default_locale",$code,($default_locale==$code),((isset($installed_locales[$code]))?'':'disabled="disabled"')) +modules/gallery/views/admin_languages.html.php 102 DIRTY $share_translations_form modules/gallery/views/admin_maintenance.html.php 24 DIRTY log::severity_class($task->severity) modules/gallery/views/admin_maintenance.html.php 24 DIRTY ($i%2==0)?"gOddRow":"gEvenRow" modules/gallery/views/admin_maintenance.html.php 26 DIRTY $task->name @@ -105,20 +105,20 @@ modules/gallery/views/admin_themes_preview.html.php 7 DIRTY $url modules/gallery/views/kohana_error_page.php 102 DIRTY $message modules/gallery/views/kohana_error_page.php 116 DIRTY $trace modules/gallery/views/kohana_profiler.php 32 DIRTY $profile->render(); -modules/gallery/views/l10n_client.html.php 20 DIRTY $string["translation"]===""?"untranslated":"translated" -modules/gallery/views/l10n_client.html.php 22 DIRTY $string["source"]["one"] -modules/gallery/views/l10n_client.html.php 23 DIRTY $string["source"]["other"] -modules/gallery/views/l10n_client.html.php 25 DIRTY $string["source"] -modules/gallery/views/l10n_client.html.php 31 DIRTY $l10n_search_form -modules/gallery/views/l10n_client.html.php 40 DIRTY access::csrf_form_field() -modules/gallery/views/l10n_client.html.php 41 DIRTY form::hidden("l10n-message-key") -modules/gallery/views/l10n_client.html.php 42 DIRTY form::textarea("l10n-edit-translation","",' rows="5" class="translationField"') -modules/gallery/views/l10n_client.html.php 45 DIRTY form::textarea("l10n-edit-plural-translation-zero","",' rows="2"') -modules/gallery/views/l10n_client.html.php 49 DIRTY form::textarea("l10n-edit-plural-translation-one","",' rows="2"') -modules/gallery/views/l10n_client.html.php 53 DIRTY form::textarea("l10n-edit-plural-translation-two","",' rows="2"') -modules/gallery/views/l10n_client.html.php 57 DIRTY form::textarea("l10n-edit-plural-translation-few","",' rows="2"') -modules/gallery/views/l10n_client.html.php 61 DIRTY form::textarea("l10n-edit-plural-translation-many","",' rows="2"') -modules/gallery/views/l10n_client.html.php 66 DIRTY form::textarea("l10n-edit-plural-translation-other","",' rows="2"') +modules/gallery/views/l10n_client.html.php 21 DIRTY $string["translation"]===""?"untranslated":"translated" +modules/gallery/views/l10n_client.html.php 23 DIRTY $string["source"]["one"] +modules/gallery/views/l10n_client.html.php 24 DIRTY $string["source"]["other"] +modules/gallery/views/l10n_client.html.php 26 DIRTY $string["source"] +modules/gallery/views/l10n_client.html.php 32 DIRTY $l10n_search_form +modules/gallery/views/l10n_client.html.php 41 DIRTY access::csrf_form_field() +modules/gallery/views/l10n_client.html.php 42 DIRTY form::hidden("l10n-message-key") +modules/gallery/views/l10n_client.html.php 43 DIRTY form::textarea("l10n-edit-translation","",' rows="5" class="translationField"') +modules/gallery/views/l10n_client.html.php 46 DIRTY form::textarea("l10n-edit-plural-translation-zero","",' rows="2"') +modules/gallery/views/l10n_client.html.php 50 DIRTY form::textarea("l10n-edit-plural-translation-one","",' rows="2"') +modules/gallery/views/l10n_client.html.php 54 DIRTY form::textarea("l10n-edit-plural-translation-two","",' rows="2"') +modules/gallery/views/l10n_client.html.php 58 DIRTY form::textarea("l10n-edit-plural-translation-few","",' rows="2"') +modules/gallery/views/l10n_client.html.php 62 DIRTY form::textarea("l10n-edit-plural-translation-many","",' rows="2"') +modules/gallery/views/l10n_client.html.php 67 DIRTY form::textarea("l10n-edit-plural-translation-other","",' rows="2"') modules/gallery/views/maintenance.html.php 46 DIRTY user::get_login_form("login/auth_html") modules/gallery/views/move_browse.html.php 39 DIRTY $tree modules/gallery/views/move_browse.html.php 43 DIRTY access::csrf_form_field() @@ -132,11 +132,11 @@ modules/gallery/views/move_tree.html.php 13 DIRTY $child modules/gallery/views/move_tree.html.php 15 DIRTY $child->id modules/gallery/views/movieplayer.html.php 2 DIRTY html::anchor($item->file_url(true),"",$attrs) modules/gallery/views/movieplayer.html.php 5 DIRTY $attrs["id"] -modules/gallery/views/permissions_browse.html.php 40 DIRTY $parent->id modules/gallery/views/permissions_browse.html.php 41 DIRTY $parent->id -modules/gallery/views/permissions_browse.html.php 46 DIRTY $item->id +modules/gallery/views/permissions_browse.html.php 42 DIRTY $parent->id modules/gallery/views/permissions_browse.html.php 47 DIRTY $item->id -modules/gallery/views/permissions_browse.html.php 54 DIRTY $form +modules/gallery/views/permissions_browse.html.php 48 DIRTY $item->id +modules/gallery/views/permissions_browse.html.php 55 DIRTY $form modules/gallery/views/permissions_form.html.php 24 DIRTY $lock->id modules/gallery/views/permissions_form.html.php 32 DIRTY $group->id modules/gallery/views/permissions_form.html.php 32 DIRTY $permission->id @@ -178,25 +178,22 @@ modules/notification/views/item_deleted.html.php 18 DIRTY $item- modules/notification/views/item_deleted.html.php 19 DIRTY $item->parent()->url(array(),true) modules/notification/views/item_updated.html.php 20 DIRTY $item->url(array(),true) modules/notification/views/item_updated.html.php 20 DIRTY $item->url(array(),true) -modules/organize/views/organize_dialog.html.php 21 DIRTY $album_tree -modules/organize/views/organize_dialog.html.php 28 DIRTY $micro_thumb_grid -modules/organize/views/organize_dialog.html.php 36 DIRTY form::dropdown(array("id"=>"gOrganizeSortColumn"),album::get_sort_order_options(),$album->sort_column) -modules/organize/views/organize_dialog.html.php 37 DIRTY form::dropdown(array("id"=>"gOrganizeSortOrder"),array("ASC"=>"Ascending","DESC"=>"Descending"),$album->sort_order) +modules/organize/views/organize_dialog.html.php 22 DIRTY $album_tree +modules/organize/views/organize_dialog.html.php 29 DIRTY $micro_thumb_grid +modules/organize/views/organize_dialog.html.php 37 DIRTY form::dropdown(array("id"=>"gOrganizeSortColumn"),album::get_sort_order_options(),$album->sort_column) +modules/organize/views/organize_dialog.html.php 38 DIRTY form::dropdown(array("id"=>"gOrganizeSortOrder"),array("ASC"=>"Ascending","DESC"=>"Descending"),$album->sort_order) modules/organize/views/organize_thumb_grid.html.php 3 DIRTY $child->id modules/organize/views/organize_thumb_grid.html.php 4 DIRTY $child->id modules/organize/views/organize_thumb_grid.html.php 5 DIRTY $child->is_album()?"gAlbum":"gPhoto" modules/organize/views/organize_thumb_grid.html.php 6 DIRTY $child->thumb_img(array("class"=>"gThumbnail","ref"=>$child->id),90,true) -modules/organize/views/organize_tree.html.php 3 DIRTY access::can("edit",$parent)?"":"gViewOnly" -modules/organize/views/organize_tree.html.php 4 DIRTY $parent->id -modules/organize/views/organize_tree.html.php 7 DIRTY $parent->id -modules/organize/views/organize_tree.html.php 14 DIRTY access::can("edit",$peer)?"":"gViewOnly" -modules/organize/views/organize_tree.html.php 15 DIRTY $peer->id -modules/organize/views/organize_tree.html.php 16 DIRTY $peer->id==$album->id?"ui-icon-minus":"ui-icon-plus" -modules/organize/views/organize_tree.html.php 18 DIRTY $peer->id==$album->id?"selected":"" -modules/organize/views/organize_tree.html.php 19 DIRTY $peer->id -modules/organize/views/organize_tree.html.php 26 DIRTY access::can("edit",$child)?"":"gViewOnly" -modules/organize/views/organize_tree.html.php 27 DIRTY $child->id -modules/organize/views/organize_tree.html.php 31 DIRTY $child->id +modules/organize/views/organize_tree.html.php 2 DIRTY access::can("edit",$album)?"":"gViewOnly" +modules/organize/views/organize_tree.html.php 3 DIRTY $album->id +modules/organize/views/organize_tree.html.php 7 DIRTY $selected&&$album->id==$selected->id?"selected":"" +modules/organize/views/organize_tree.html.php 9 DIRTY $album->id +modules/organize/views/organize_tree.html.php 15 DIRTY View::factory("organize_tree.html",array("selected"=>$selected,"album"=>$child)); +modules/organize/views/organize_tree.html.php 17 DIRTY access::can("edit",$child)?"":"gViewOnly" +modules/organize/views/organize_tree.html.php 18 DIRTY $child->id +modules/organize/views/organize_tree.html.php 21 DIRTY $child->id modules/recaptcha/views/admin_recaptcha.html.php 10 DIRTY $form modules/recaptcha/views/admin_recaptcha.html.php 23 DIRTY $public_key modules/recaptcha/views/form_recaptcha.html.php 7 DIRTY $public_key -- cgit v1.2.3 From 0a0c7a78e6333728bad19611cccb095241545cc6 Mon Sep 17 00:00:00 2001 From: Andy Staudacher Date: Sun, 30 Aug 2009 21:25:21 -0700 Subject: Check for href="" (malicious "javascript:..." string) --- modules/gallery/tests/Xss_Security_Test.php | 47 +++++++++++++++++++++++------ 1 file changed, 37 insertions(+), 10 deletions(-) diff --git a/modules/gallery/tests/Xss_Security_Test.php b/modules/gallery/tests/Xss_Security_Test.php index 6c141c52..ef36f6b7 100644 --- a/modules/gallery/tests/Xss_Security_Test.php +++ b/modules/gallery/tests/Xss_Security_Test.php @@ -32,6 +32,7 @@ class Xss_Security_Test extends Unit_Test_Case { $frame = null; $script_block = 0; $in_script_block = false; + $inline_html = ""; for ($token_number = 0; $token_number < count($tokens); $token_number++) { $token = $tokens[$token_number]; @@ -81,6 +82,8 @@ class Xss_Security_Test extends Unit_Test_Case { } } + $href_attribute_start = preg_match('{href\s*=\s*[\'"]?\s*$}i', str_replace("\n", "", $inline_html)); + // Look and report each instance of < ? = ... ? > if (!is_array($token)) { // A single char token, e.g: ; ( ) @@ -89,7 +92,8 @@ class Xss_Security_Test extends Unit_Test_Case { } } else if ($token[0] == T_OPEN_TAG_WITH_ECHO) { // No need for a stack here - assume < ? = cannot be nested. - $frame = self::_create_frame($token, $in_script_block); + $frame = self::_create_frame($token, $in_script_block, $href_attribute_start); + $href_attribute_start = false; } else if ($frame && $token[0] == T_CLOSE_TAG) { // Store the < ? = ... ? > block that just ended here. $found[$view][] = $frame; @@ -177,6 +181,7 @@ class Xss_Security_Test extends Unit_Test_Case { "abs_file", "merge")) && self::_token_matches("(", $tokens, $token_number + 3)) { $frame->is_safe_html(true); + $frame->is_safe_href_attr(true); $method = $tokens[$token_number + 2][1]; $frame->expr_append("::$method("); @@ -237,6 +242,8 @@ class Xss_Security_Test extends Unit_Test_Case { * DIRTY_JS: * In }i', $inline_html, $matches, PREG_OFFSET_CAPTURE)) { $last_match = array_pop($matches[0]); if (is_array($last_match)) { @@ -75,7 +76,7 @@ class Xss_Security_Test extends Unit_Test_Case { $closing_script_pos = $last_match; } } - if (preg_match('{]*>}i', $inline_html, $matches, PREG_OFFSET_CAPTURE)) { + if (preg_match_all('{]*>}i', $inline_html, $matches, PREG_OFFSET_CAPTURE)) { $last_match = array_pop($matches[0]); if (is_array($last_match)) { $opening_script_pos = $last_match[1]; -- cgit v1.2.3 From d2cea7905e342c2a9a7cec03058ab762d0d1ba7f Mon Sep 17 00:00:00 2001 From: Andy Staudacher Date: Tue, 1 Sep 2009 00:53:17 -0700 Subject: Remove debugging code --- modules/gallery/tests/Xss_Security_Test.php | 1 - 1 file changed, 1 deletion(-) diff --git a/modules/gallery/tests/Xss_Security_Test.php b/modules/gallery/tests/Xss_Security_Test.php index 34ecc4fe..85624517 100644 --- a/modules/gallery/tests/Xss_Security_Test.php +++ b/modules/gallery/tests/Xss_Security_Test.php @@ -21,7 +21,6 @@ class Xss_Security_Test extends Unit_Test_Case { public function find_unescaped_variables_in_views_test() { $found = array(); foreach (glob("*/*/views/*.php") as $view) { - if ($view != "modules/tag/views/admin_tags.html.php") continue; // List of all tokens without whitespace, simplifying parsing. $tokens = array(); foreach (token_get_all(file_get_contents($view)) as $token) { -- cgit v1.2.3 From ff1979e12e0b012374e2ab3712b19f87e1a92e64 Mon Sep 17 00:00:00 2001 From: Andy Staudacher Date: Tue, 1 Sep 2009 01:12:02 -0700 Subject: Fix XSS in tags JS --- modules/tag/js/tag.js | 10 ++++++++-- modules/tag/views/admin_tags.html.php | 8 ++++---- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/modules/tag/js/tag.js b/modules/tag/js/tag.js index 61ac73f4..aaae9e72 100644 --- a/modules/tag/js/tag.js +++ b/modules/tag/js/tag.js @@ -27,18 +27,24 @@ function closeEditInPlaceForms() { } } +function str_replace(search_term, replacement, string) { + var temp = string.split(search_term); + return temp.join(replacement); +} + function editInPlace(element) { closeEditInPlaceForms(); // create edit form var tag_id = $(this).attr('id').substr(5); - var tag_name = $(this).text(); + var tag_name = $(this).html(); var tag_width = $(this).width(); $(this).parent().data("revert", $(this).parent().html()); var form = '
                  '; form += ''; - form += ''; + form += ''; form += ''; form += '' + cancel_i18n + ''; form += '
                  '; diff --git a/modules/tag/views/admin_tags.html.php b/modules/tag/views/admin_tags.html.php index 3d805c5e..8f3693aa 100644 --- a/modules/tag/views/admin_tags.html.php +++ b/modules/tag/views/admin_tags.html.php @@ -1,9 +1,9 @@

                  -- cgit v1.2.3 From 94c201f265c758fad38eb69c0a5878970119197a Mon Sep 17 00:00:00 2001 From: Andy Staudacher Date: Tue, 1 Sep 2009 01:17:39 -0700 Subject: XSS escape in form helper and forge where missing. --- modules/forge/libraries/Form_Checkbox.php | 2 +- modules/forge/libraries/Form_Checklist.php | 2 +- modules/forge/libraries/Form_Group.php | 2 +- system/helpers/form.php | 19 +++++++++++++------ 4 files changed, 16 insertions(+), 9 deletions(-) diff --git a/modules/forge/libraries/Form_Checkbox.php b/modules/forge/libraries/Form_Checkbox.php index b94fc438..aded4fdf 100644 --- a/modules/forge/libraries/Form_Checkbox.php +++ b/modules/forge/libraries/Form_Checkbox.php @@ -68,7 +68,7 @@ class Form_Checkbox_Core extends Form_Input { $label = ' '.ltrim($label); } - return ''; + return ''; } protected function load_value() diff --git a/modules/forge/libraries/Form_Checklist.php b/modules/forge/libraries/Form_Checklist.php index 99b455bd..4536d396 100644 --- a/modules/forge/libraries/Form_Checklist.php +++ b/modules/forge/libraries/Form_Checklist.php @@ -67,7 +67,7 @@ class Form_Checklist_Core extends Form_Input { $data['value'] = $val; $data['checked'] = $checked; - $checklist .= '
                • '.$nl; + $checklist .= '
                • '.$nl; } $checklist .= '

                '; diff --git a/modules/forge/libraries/Form_Group.php b/modules/forge/libraries/Form_Group.php index 29eff510..e0601321 100644 --- a/modules/forge/libraries/Form_Group.php +++ b/modules/forge/libraries/Form_Group.php @@ -57,7 +57,7 @@ class Form_Group_Core extends Forge { { if ($label = $this->data['label']) { - return $this->data['label']; + return html::purify($this->data['label']); } } else diff --git a/system/helpers/form.php b/system/helpers/form.php index ce8767c5..815eef84 100644 --- a/system/helpers/form.php +++ b/system/helpers/form.php @@ -283,15 +283,21 @@ class form_Core { // Inner key should always be a string $inner_key = (string) $inner_key; - $sel = in_array($inner_key, $selected) ? ' selected="selected"' : ''; - $input .= ''."\n"; + $attr = array('value' => $inner_key); + if (in_array($inner_key, $selected)) { + $attr['selected'] = 'selected'; + } + $input .= ''."\n"; } $input .= ''."\n"; } else { - $sel = in_array($key, $selected) ? ' selected="selected"' : ''; - $input .= ''."\n"; + $attr = array('value' => $key); + if (in_array($key, $selected)) { + $attr['selected'] = 'selected'; + } + $input .= ''."\n"; } } $input .= ''; @@ -410,8 +416,9 @@ class form_Core { { $value = arr::remove('value', $data); } + // $value must be ::purify - return ''.$value.''; + return ''.html::purify($value).''; } /** @@ -455,7 +462,7 @@ class form_Core { $text = ucwords(inflector::humanize($data['for'])); } - return ''.$text.''; + return ''.html::purify($text).''; } /** -- cgit v1.2.3 From 53711225ac9d116e72c159de943284fd55fe26e4 Mon Sep 17 00:00:00 2001 From: Andy Staudacher Date: Tue, 1 Sep 2009 01:28:52 -0700 Subject: XSS / style fixes for newly detected issues (after fixing XSS scanner) --- modules/comment/views/admin_comments.html.php | 6 +++--- modules/gallery/views/admin_dashboard.html.php | 2 +- modules/gallery/views/admin_graphics.html.php | 2 +- modules/gallery/views/admin_maintenance_task.html.php | 2 +- modules/recaptcha/views/admin_recaptcha.html.php | 4 ++-- modules/recaptcha/views/form_recaptcha.html.php | 2 +- modules/user/views/login_ajax.html.php | 2 +- 7 files changed, 10 insertions(+), 10 deletions(-) diff --git a/modules/comment/views/admin_comments.html.php b/modules/comment/views/admin_comments.html.php index f5970ae1..455cd714 100644 --- a/modules/comment/views/admin_comments.html.php +++ b/modules/comment/views/admin_comments.html.php @@ -1,7 +1,7 @@ diff --git a/modules/recaptcha/views/form_recaptcha.html.php b/modules/recaptcha/views/form_recaptcha.html.php index d4031586..4ec04c49 100644 --- a/modules/recaptcha/views/form_recaptcha.html.php +++ b/modules/recaptcha/views/form_recaptcha.html.php @@ -8,7 +8,7 @@ "gRecaptcha", { theme: "white", - custom_translations : { instructions_visual : ""}, + custom_translations : { instructions_visual : for_js() ?>}, callback: Recaptcha.focus_response_field } ); diff --git a/modules/user/views/login_ajax.html.php b/modules/user/views/login_ajax.html.php index d697c958..56bc1cbd 100644 --- a/modules/user/views/login_ajax.html.php +++ b/modules/user/views/login_ajax.html.php @@ -6,7 +6,7 @@ url: "", success: function(data) { $("div#gLoginView").html(data); - $("#ui-dialog-title-gDialog").text(""); + $("#ui-dialog-title-gDialog").html(for_js() ?>); ajaxify_login_reset_form(); } }); -- cgit v1.2.3 From fe37483aca648b6f7de65f1eb53b8cfd49401f71 Mon Sep 17 00:00:00 2001 From: Andy Staudacher Date: Tue, 1 Sep 2009 01:29:42 -0700 Subject: Update XSS scanner golden file --- modules/gallery/tests/xss_data.txt | 30 ++++++++++++++++++++++++------ 1 file changed, 24 insertions(+), 6 deletions(-) diff --git a/modules/gallery/tests/xss_data.txt b/modules/gallery/tests/xss_data.txt index fa1f8cdf..7e536e90 100644 --- a/modules/gallery/tests/xss_data.txt +++ b/modules/gallery/tests/xss_data.txt @@ -50,7 +50,7 @@ modules/gallery/views/admin_block_news.html.php 5 DIRTY $entry modules/gallery/views/admin_block_news.html.php 7 DIRTY text::limit_words(strip_tags($entry["description"]),25); 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 $csrf +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_graphics.html.php 22 DIRTY newView("admin_graphics_none.html") modules/gallery/views/admin_graphics.html.php 24 DIRTY newView("admin_graphics_$active.html",array("tk"=>$tk->$active,"is_active"=>true)) @@ -88,6 +88,7 @@ modules/gallery/views/admin_maintenance.html.php 146 DIRTY_ATTR $tas modules/gallery/views/admin_maintenance.html.php 147 DIRTY gallery::date_time($task->updated) modules/gallery/views/admin_maintenance.html.php 150 DIRTY $task->name modules/gallery/views/admin_maintenance.html.php 162 DIRTY $task->status +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 55 DIRTY $task->name modules/gallery/views/admin_modules.html.php 9 DIRTY access::csrf_form_field() @@ -95,7 +96,8 @@ modules/gallery/views/admin_modules.html.php 19 DIRTY_ATTR ($i% modules/gallery/views/admin_modules.html.php 22 DIRTY form::checkbox($data,'1',module::is_active($module_name)) modules/gallery/views/admin_modules.html.php 24 DIRTY $module_info->version modules/gallery/views/admin_theme_options.html.php 5 DIRTY $form -modules/gallery/views/admin_themes.html.php 5 DIRTY $csrf +modules/gallery/views/admin_themes.html.php 3 DIRTY_JS url::site("admin/themes/choose") +modules/gallery/views/admin_themes.html.php 5 DIRTY_JS $csrf modules/gallery/views/admin_themes.html.php 20 DIRTY $themes[$site]->name modules/gallery/views/admin_themes.html.php 22 DIRTY $themes[$site]->description modules/gallery/views/admin_themes.html.php 36 DIRTY $info->name @@ -123,6 +125,7 @@ modules/gallery/views/l10n_client.html.php 58 DIRTY form:: modules/gallery/views/l10n_client.html.php 62 DIRTY form::textarea("l10n-edit-plural-translation-many","",' rows="2"') modules/gallery/views/l10n_client.html.php 67 DIRTY form::textarea("l10n-edit-plural-translation-other","",' rows="2"') modules/gallery/views/maintenance.html.php 46 DIRTY user::get_login_form("login/auth_html") +modules/gallery/views/move_browse.html.php 4 DIRTY_JS url::site("move/show_sub_tree/{$source->id}/__TARGETID__") modules/gallery/views/move_browse.html.php 39 DIRTY $tree modules/gallery/views/move_browse.html.php 43 DIRTY access::csrf_form_field() modules/gallery/views/move_tree.html.php 2 DIRTY $parent->thumb_img(array(),25); @@ -134,7 +137,11 @@ modules/gallery/views/move_tree.html.php 11 DIRTY $child modules/gallery/views/move_tree.html.php 13 DIRTY_JS $child->id modules/gallery/views/move_tree.html.php 15 DIRTY_JS $child->id modules/gallery/views/movieplayer.html.php 2 DIRTY html::anchor($item->file_url(true),"",$attrs) -modules/gallery/views/movieplayer.html.php 5 DIRTY $attrs["id"] +modules/gallery/views/movieplayer.html.php 5 DIRTY_JS $attrs["id"] +modules/gallery/views/movieplayer.html.php 7 DIRTY_JS url::abs_file("lib/flowplayer.swf") +modules/gallery/views/movieplayer.html.php 13 DIRTY_JS url::abs_file("lib/flowplayer.h264streaming.swf") +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 41 DIRTY_ATTR $parent->id modules/gallery/views/permissions_browse.html.php 42 DIRTY_JS $parent->id modules/gallery/views/permissions_browse.html.php 47 DIRTY_ATTR $item->id @@ -181,6 +188,10 @@ modules/notification/views/item_deleted.html.php 18 DIRTY_JS $item- modules/notification/views/item_deleted.html.php 19 DIRTY $item->parent()->url(array(),true) modules/notification/views/item_updated.html.php 20 DIRTY_JS $item->url(array(),true) modules/notification/views/item_updated.html.php 20 DIRTY $item->url(array(),true) +modules/organize/views/organize_dialog.html.php 3 DIRTY_JS url::site("organize/move_to/__ALBUM_ID__?csrf=$csrf") +modules/organize/views/organize_dialog.html.php 4 DIRTY_JS url::site("organize/rearrange/__TARGET_ID__/__BEFORE__?csrf=$csrf") +modules/organize/views/organize_dialog.html.php 5 DIRTY_JS url::site("organize/sort_order/__ALBUM_ID__/__COL__/__DIR__?csrf=$csrf") +modules/organize/views/organize_dialog.html.php 6 DIRTY_JS url::site("organize/tree/__ALBUM_ID__") modules/organize/views/organize_dialog.html.php 22 DIRTY $album_tree modules/organize/views/organize_dialog.html.php 29 DIRTY $micro_thumb_grid modules/organize/views/organize_dialog.html.php 37 DIRTY form::dropdown(array("id"=>"gOrganizeSortColumn"),album::get_sort_order_options(),$album->sort_column) @@ -189,6 +200,7 @@ modules/organize/views/organize_thumb_grid.html.php 3 DIRTY_ATTR $chi modules/organize/views/organize_thumb_grid.html.php 4 DIRTY_ATTR $child->id modules/organize/views/organize_thumb_grid.html.php 5 DIRTY_ATTR $child->is_album()?"gAlbum":"gPhoto" modules/organize/views/organize_thumb_grid.html.php 6 DIRTY $child->thumb_img(array("class"=>"gThumbnail","ref"=>$child->id),90,true) +modules/organize/views/organize_thumb_grid.html.php 14 DIRTY_JS url::site("organize/content/$album->id/".($offset+25)) modules/organize/views/organize_tree.html.php 2 DIRTY_ATTR access::can("edit",$album)?"":"gViewOnly" modules/organize/views/organize_tree.html.php 3 DIRTY_ATTR $album->id modules/organize/views/organize_tree.html.php 6 DIRTY_ATTR $selected&&$album->id==$selected->id?"selected":"" @@ -198,8 +210,8 @@ modules/organize/views/organize_tree.html.php 15 DIRTY_ATTR acce modules/organize/views/organize_tree.html.php 16 DIRTY_ATTR $child->id modules/organize/views/organize_tree.html.php 19 DIRTY_ATTR $child->id modules/recaptcha/views/admin_recaptcha.html.php 10 DIRTY $form -modules/recaptcha/views/admin_recaptcha.html.php 23 DIRTY $public_key -modules/recaptcha/views/form_recaptcha.html.php 7 DIRTY $public_key +modules/recaptcha/views/admin_recaptcha.html.php 23 DIRTY_JS $public_key +modules/recaptcha/views/form_recaptcha.html.php 7 DIRTY_JS $public_key modules/rss/views/feed.mrss.php 10 DIRTY $feed->uri modules/rss/views/feed.mrss.php 13 DIRTY_JS $feed->uri modules/rss/views/feed.mrss.php 16 DIRTY_JS $feed->previous_page_uri @@ -239,14 +251,19 @@ modules/server_add/views/admin_server_add.html.php 15 DIRTY_ATTR $id modules/server_add/views/admin_server_add.html.php 24 DIRTY $form modules/server_add/views/server_add_tree.html.php 12 DIRTY_JS html::js_string($dir) 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_dialog.html.php 3 DIRTY_JS url::site("server_add/children?path=__PATH__") +modules/server_add/views/server_add_tree_dialog.html.php 4 DIRTY_JS url::site("server_add/start?item_id={$item->id}&csrf=$csrf") modules/server_add/views/server_add_tree_dialog.html.php 23 DIRTY $tree -modules/tag/views/admin_tags.html.php 13 DIRTY $csrf +modules/tag/views/admin_tags.html.php 13 DIRTY_JS $csrf modules/tag/views/admin_tags.html.php 50 DIRTY_ATTR $tag->id modules/tag/views/admin_tags.html.php 51 DIRTY $tag->count modules/tag/views/tag_block.html.php 15 DIRTY $cloud modules/tag/views/tag_block.html.php 17 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/user/views/admin_users.html.php 3 DIRTY_JS url::site("admin/users/add_user_to_group/__USERID__/__GROUPID__?csrf=$csrf") +modules/user/views/admin_users.html.php 26 DIRTY_JS url::site("admin/users/group/__GROUPID__") +modules/user/views/admin_users.html.php 36 DIRTY_JS url::site("admin/users/remove_user_from_group/__USERID__/__GROUPID__?csrf=$csrf") modules/user/views/admin_users.html.php 67 DIRTY_ATTR $user->id modules/user/views/admin_users.html.php 67 DIRTY_ATTR text::alternate("gOddRow","gEvenRow") modules/user/views/admin_users.html.php 67 DIRTY_ATTR $user->admin?"admin":"" @@ -258,6 +275,7 @@ modules/user/views/admin_users.html.php 121 DIRTY_ATTR ($gr modules/user/views/admin_users.html.php 123 DIRTY $v modules/user/views/admin_users_group.html.php 22 DIRTY_JS $user->id modules/user/views/admin_users_group.html.php 22 DIRTY_JS $group->id +modules/user/views/login_ajax.html.php 6 DIRTY_JS url::site("password/reset") modules/user/views/login_ajax.html.php 37 DIRTY $form modules/watermark/views/admin_watermarks.html.php 19 DIRTY_ATTR $width modules/watermark/views/admin_watermarks.html.php 19 DIRTY_ATTR $height -- cgit v1.2.3 From b50d7f0d69122e15a91b9838eedeeb5c922040bb Mon Sep 17 00:00:00 2001 From: Andy Staudacher Date: Tue, 1 Sep 2009 11:11:22 -0700 Subject: Fix bug #522 - Handle "save settings" correctly in the "share translations" form. --- modules/gallery/controllers/admin_languages.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/gallery/controllers/admin_languages.php b/modules/gallery/controllers/admin_languages.php index 894daedb..d91e5205 100644 --- a/modules/gallery/controllers/admin_languages.php +++ b/modules/gallery/controllers/admin_languages.php @@ -61,7 +61,7 @@ class Admin_Languages_Controller extends Admin_Controller { return $this->index($form); } - if ($form->sharing->share) { + if ($this->input->post("share")) { l10n_client::submit_translations(); message::success(t("Translations submitted")); } else { -- cgit v1.2.3 From 1d3069145273bcb3514f08fa9eee2dbf55a07b01 Mon Sep 17 00:00:00 2001 From: Andy Staudacher Date: Tue, 1 Sep 2009 12:14:23 -0700 Subject: Add missing mark_clean() for t() calls with %attr parameter. --- modules/comment/views/comments.html.php | 2 +- modules/recaptcha/views/admin_recaptcha.html.php | 2 +- themes/default/views/album.html.php | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/modules/comment/views/comments.html.php b/modules/comment/views/comments.html.php index b7ebdf3a..7eb34c20 100644 --- a/modules/comment/views/comments.html.php +++ b/modules/comment/views/comments.html.php @@ -8,7 +8,7 @@ count()): ?>

                comment!", - array("attrs" => "href=\"#add_comment_form\" class=\"showCommentForm\"")) ?> + array("attrs" => html::mark_clean("href=\"#add_comment_form\" class=\"showCommentForm\""))) ?>

                  diff --git a/modules/recaptcha/views/admin_recaptcha.html.php b/modules/recaptcha/views/admin_recaptcha.html.php index 35722be4..0a4b1f8f 100644 --- a/modules/recaptcha/views/admin_recaptcha.html.php +++ b/modules/recaptcha/views/admin_recaptcha.html.php @@ -4,7 +4,7 @@

                  reCAPTCHA Public/Private Key pair, which is also free. Once registered, the challenge and response strings are evaluated at recaptcha.net to determine if the form content has been entered by a bot.", array("domain_url" => $form->get_key_url, - "recaptcha_url" => html::mark_safe("http://recaptcha.net"))) ?> + "recaptcha_url" => html::mark_clean("http://recaptcha.net"))) ?>

                  diff --git a/themes/default/views/album.html.php b/themes/default/views/album.html.php index caabeee3..8bc81a31 100644 --- a/themes/default/views/album.html.php +++ b/themes/default/views/album.html.php @@ -30,7 +30,7 @@ admin || access::can("add", $item)): ?> id") ?>
                • Add some.", - array("attrs" => "href=\"$addurl\" class=\"gDialogLink\"")) ?>
                • + array("attrs" => html::mark_clean("href=\"$addurl\" class=\"gDialogLink\""))) ?>
                • -- cgit v1.2.3 From 95ea310aff41f7c16b0a48ec35a5f47c32a4d801 Mon Sep 17 00:00:00 2001 From: Andy Staudacher Date: Tue, 1 Sep 2009 14:39:08 -0700 Subject: Remove unused l10n message --- modules/gallery/views/l10n_client.html.php | 1 - 1 file changed, 1 deletion(-) diff --git a/modules/gallery/views/l10n_client.html.php b/modules/gallery/views/l10n_client.html.php index 3a43f7d3..b0f424be 100644 --- a/modules/gallery/views/l10n_client.html.php +++ b/modules/gallery/views/l10n_client.html.php @@ -74,7 +74,6 @@
                )#si', - array($this, 'scriptCallback'), $html); - } - - $html = $this->normalize($html, $config, $context); - - $cursor = 0; // our location in the text - $inside_tag = false; // whether or not we're parsing the inside of a tag - $array = array(); // result array - - // This is also treated to mean maintain *column* numbers too - $maintain_line_numbers = $config->get('Core.MaintainLineNumbers'); - - if ($maintain_line_numbers === null) { - // automatically determine line numbering by checking - // if error collection is on - $maintain_line_numbers = $config->get('Core.CollectErrors'); - } - - if ($maintain_line_numbers) { - $current_line = 1; - $current_col = 0; - $length = strlen($html); - } else { - $current_line = false; - $current_col = false; - $length = false; - } - $context->register('CurrentLine', $current_line); - $context->register('CurrentCol', $current_col); - $nl = "\n"; - // how often to manually recalculate. This will ALWAYS be right, - // but it's pretty wasteful. Set to 0 to turn off - $synchronize_interval = $config->get('Core.DirectLexLineNumberSyncInterval'); - - $e = false; - if ($config->get('Core.CollectErrors')) { - $e =& $context->get('ErrorCollector'); - } - - // for testing synchronization - $loops = 0; - - while(++$loops) { - - // $cursor is either at the start of a token, or inside of - // a tag (i.e. there was a < immediately before it), as indicated - // by $inside_tag - - if ($maintain_line_numbers) { - - // $rcursor, however, is always at the start of a token. - $rcursor = $cursor - (int) $inside_tag; - - // Column number is cheap, so we calculate it every round. - // We're interested at the *end* of the newline string, so - // we need to add strlen($nl) == 1 to $nl_pos before subtracting it - // from our "rcursor" position. - $nl_pos = strrpos($html, $nl, $rcursor - $length); - $current_col = $rcursor - (is_bool($nl_pos) ? 0 : $nl_pos + 1); - - // recalculate lines - if ( - $synchronize_interval && // synchronization is on - $cursor > 0 && // cursor is further than zero - $loops % $synchronize_interval === 0 // time to synchronize! - ) { - $current_line = 1 + $this->substrCount($html, $nl, 0, $cursor); - } - - } - - $position_next_lt = strpos($html, '<', $cursor); - $position_next_gt = strpos($html, '>', $cursor); - - // triggers on "asdf" but not "asdf " - // special case to set up context - if ($position_next_lt === $cursor) { - $inside_tag = true; - $cursor++; - } - - if (!$inside_tag && $position_next_lt !== false) { - // We are not inside tag and there still is another tag to parse - $token = new - HTMLPurifier_Token_Text( - $this->parseData( - substr( - $html, $cursor, $position_next_lt - $cursor - ) - ) - ); - if ($maintain_line_numbers) { - $token->rawPosition($current_line, $current_col); - $current_line += $this->substrCount($html, $nl, $cursor, $position_next_lt - $cursor); - } - $array[] = $token; - $cursor = $position_next_lt + 1; - $inside_tag = true; - continue; - } elseif (!$inside_tag) { - // We are not inside tag but there are no more tags - // If we're already at the end, break - if ($cursor === strlen($html)) break; - // Create Text of rest of string - $token = new - HTMLPurifier_Token_Text( - $this->parseData( - substr( - $html, $cursor - ) - ) - ); - if ($maintain_line_numbers) $token->rawPosition($current_line, $current_col); - $array[] = $token; - break; - } elseif ($inside_tag && $position_next_gt !== false) { - // We are in tag and it is well formed - // Grab the internals of the tag - $strlen_segment = $position_next_gt - $cursor; - - if ($strlen_segment < 1) { - // there's nothing to process! - $token = new HTMLPurifier_Token_Text('<'); - $cursor++; - continue; - } - - $segment = substr($html, $cursor, $strlen_segment); - - if ($segment === false) { - // somehow, we attempted to access beyond the end of - // the string, defense-in-depth, reported by Nate Abele - break; - } - - // Check if it's a comment - if ( - substr($segment, 0, 3) === '!--' - ) { - // re-determine segment length, looking for --> - $position_comment_end = strpos($html, '-->', $cursor); - if ($position_comment_end === false) { - // uh oh, we have a comment that extends to - // infinity. Can't be helped: set comment - // end position to end of string - if ($e) $e->send(E_WARNING, 'Lexer: Unclosed comment'); - $position_comment_end = strlen($html); - $end = true; - } else { - $end = false; - } - $strlen_segment = $position_comment_end - $cursor; - $segment = substr($html, $cursor, $strlen_segment); - $token = new - HTMLPurifier_Token_Comment( - substr( - $segment, 3, $strlen_segment - 3 - ) - ); - if ($maintain_line_numbers) { - $token->rawPosition($current_line, $current_col); - $current_line += $this->substrCount($html, $nl, $cursor, $strlen_segment); - } - $array[] = $token; - $cursor = $end ? $position_comment_end : $position_comment_end + 3; - $inside_tag = false; - continue; - } - - // Check if it's an end tag - $is_end_tag = (strpos($segment,'/') === 0); - if ($is_end_tag) { - $type = substr($segment, 1); - $token = new HTMLPurifier_Token_End($type); - if ($maintain_line_numbers) { - $token->rawPosition($current_line, $current_col); - $current_line += $this->substrCount($html, $nl, $cursor, $position_next_gt - $cursor); - } - $array[] = $token; - $inside_tag = false; - $cursor = $position_next_gt + 1; - continue; - } - - // Check leading character is alnum, if not, we may - // have accidently grabbed an emoticon. Translate into - // text and go our merry way - if (!ctype_alpha($segment[0])) { - // XML: $segment[0] !== '_' && $segment[0] !== ':' - if ($e) $e->send(E_NOTICE, 'Lexer: Unescaped lt'); - $token = new HTMLPurifier_Token_Text('<'); - if ($maintain_line_numbers) { - $token->rawPosition($current_line, $current_col); - $current_line += $this->substrCount($html, $nl, $cursor, $position_next_gt - $cursor); - } - $array[] = $token; - $inside_tag = false; - continue; - } - - // Check if it is explicitly self closing, if so, remove - // trailing slash. Remember, we could have a tag like
                , so - // any later token processing scripts must convert improperly - // classified EmptyTags from StartTags. - $is_self_closing = (strrpos($segment,'/') === $strlen_segment-1); - if ($is_self_closing) { - $strlen_segment--; - $segment = substr($segment, 0, $strlen_segment); - } - - // Check if there are any attributes - $position_first_space = strcspn($segment, $this->_whitespace); - - if ($position_first_space >= $strlen_segment) { - if ($is_self_closing) { - $token = new HTMLPurifier_Token_Empty($segment); - } else { - $token = new HTMLPurifier_Token_Start($segment); - } - if ($maintain_line_numbers) { - $token->rawPosition($current_line, $current_col); - $current_line += $this->substrCount($html, $nl, $cursor, $position_next_gt - $cursor); - } - $array[] = $token; - $inside_tag = false; - $cursor = $position_next_gt + 1; - continue; - } - - // Grab out all the data - $type = substr($segment, 0, $position_first_space); - $attribute_string = - trim( - substr( - $segment, $position_first_space - ) - ); - if ($attribute_string) { - $attr = $this->parseAttributeString( - $attribute_string - , $config, $context - ); - } else { - $attr = array(); - } - - if ($is_self_closing) { - $token = new HTMLPurifier_Token_Empty($type, $attr); - } else { - $token = new HTMLPurifier_Token_Start($type, $attr); - } - if ($maintain_line_numbers) { - $token->rawPosition($current_line, $current_col); - $current_line += $this->substrCount($html, $nl, $cursor, $position_next_gt - $cursor); - } - $array[] = $token; - $cursor = $position_next_gt + 1; - $inside_tag = false; - continue; - } else { - // inside tag, but there's no ending > sign - if ($e) $e->send(E_WARNING, 'Lexer: Missing gt'); - $token = new - HTMLPurifier_Token_Text( - '<' . - $this->parseData( - substr($html, $cursor) - ) - ); - if ($maintain_line_numbers) $token->rawPosition($current_line, $current_col); - // no cursor scroll? Hmm... - $array[] = $token; - break; - } - break; - } - - $context->destroy('CurrentLine'); - $context->destroy('CurrentCol'); - return $array; - } - - /** - * PHP 5.0.x compatible substr_count that implements offset and length - */ - protected function substrCount($haystack, $needle, $offset, $length) { - static $oldVersion; - if ($oldVersion === null) { - $oldVersion = version_compare(PHP_VERSION, '5.1', '<'); - } - if ($oldVersion) { - $haystack = substr($haystack, $offset, $length); - return substr_count($haystack, $needle); - } else { - return substr_count($haystack, $needle, $offset, $length); - } - } - - /** - * Takes the inside of an HTML tag and makes an assoc array of attributes. - * - * @param $string Inside of tag excluding name. - * @returns Assoc array of attributes. - */ - public function parseAttributeString($string, $config, $context) { - $string = (string) $string; // quick typecast - - if ($string == '') return array(); // no attributes - - $e = false; - if ($config->get('Core.CollectErrors')) { - $e =& $context->get('ErrorCollector'); - } - - // let's see if we can abort as quickly as possible - // one equal sign, no spaces => one attribute - $num_equal = substr_count($string, '='); - $has_space = strpos($string, ' '); - if ($num_equal === 0 && !$has_space) { - // bool attribute - return array($string => $string); - } elseif ($num_equal === 1 && !$has_space) { - // only one attribute - list($key, $quoted_value) = explode('=', $string); - $quoted_value = trim($quoted_value); - if (!$key) { - if ($e) $e->send(E_ERROR, 'Lexer: Missing attribute key'); - return array(); - } - if (!$quoted_value) return array($key => ''); - $first_char = @$quoted_value[0]; - $last_char = @$quoted_value[strlen($quoted_value)-1]; - - $same_quote = ($first_char == $last_char); - $open_quote = ($first_char == '"' || $first_char == "'"); - - if ( $same_quote && $open_quote) { - // well behaved - $value = substr($quoted_value, 1, strlen($quoted_value) - 2); - } else { - // not well behaved - if ($open_quote) { - if ($e) $e->send(E_ERROR, 'Lexer: Missing end quote'); - $value = substr($quoted_value, 1); - } else { - $value = $quoted_value; - } - } - if ($value === false) $value = ''; - return array($key => $value); - } - - // setup loop environment - $array = array(); // return assoc array of attributes - $cursor = 0; // current position in string (moves forward) - $size = strlen($string); // size of the string (stays the same) - - // if we have unquoted attributes, the parser expects a terminating - // space, so let's guarantee that there's always a terminating space. - $string .= ' '; - - while(true) { - - if ($cursor >= $size) { - break; - } - - $cursor += ($value = strspn($string, $this->_whitespace, $cursor)); - // grab the key - - $key_begin = $cursor; //we're currently at the start of the key - - // scroll past all characters that are the key (not whitespace or =) - $cursor += strcspn($string, $this->_whitespace . '=', $cursor); - - $key_end = $cursor; // now at the end of the key - - $key = substr($string, $key_begin, $key_end - $key_begin); - - if (!$key) { - if ($e) $e->send(E_ERROR, 'Lexer: Missing attribute key'); - $cursor += strcspn($string, $this->_whitespace, $cursor + 1); // prevent infinite loop - continue; // empty key - } - - // scroll past all whitespace - $cursor += strspn($string, $this->_whitespace, $cursor); - - if ($cursor >= $size) { - $array[$key] = $key; - break; - } - - // if the next character is an equal sign, we've got a regular - // pair, otherwise, it's a bool attribute - $first_char = @$string[$cursor]; - - if ($first_char == '=') { - // key="value" - - $cursor++; - $cursor += strspn($string, $this->_whitespace, $cursor); - - if ($cursor === false) { - $array[$key] = ''; - break; - } - - // we might be in front of a quote right now - - $char = @$string[$cursor]; - - if ($char == '"' || $char == "'") { - // it's quoted, end bound is $char - $cursor++; - $value_begin = $cursor; - $cursor = strpos($string, $char, $cursor); - $value_end = $cursor; - } else { - // it's not quoted, end bound is whitespace - $value_begin = $cursor; - $cursor += strcspn($string, $this->_whitespace, $cursor); - $value_end = $cursor; - } - - // we reached a premature end - if ($cursor === false) { - $cursor = $size; - $value_end = $cursor; - } - - $value = substr($string, $value_begin, $value_end - $value_begin); - if ($value === false) $value = ''; - $array[$key] = $this->parseData($value); - $cursor++; - - } else { - // boolattr - if ($key !== '') { - $array[$key] = $key; - } else { - // purely theoretical - if ($e) $e->send(E_ERROR, 'Lexer: Missing attribute key'); - } - - } - } - return $array; - } - -} - -// vim: et sw=4 sts=4 diff --git a/modules/gallery/lib/HTMLPurifier/HTMLPurifier/Lexer/PEARSax3.php b/modules/gallery/lib/HTMLPurifier/HTMLPurifier/Lexer/PEARSax3.php deleted file mode 100644 index 57173455..00000000 --- a/modules/gallery/lib/HTMLPurifier/HTMLPurifier/Lexer/PEARSax3.php +++ /dev/null @@ -1,106 +0,0 @@ -tokens = array(); - - $string = $this->normalize($string, $config, $context); - - $parser = new XML_HTMLSax3(); - $parser->set_object($this); - $parser->set_element_handler('openHandler','closeHandler'); - $parser->set_data_handler('dataHandler'); - $parser->set_escape_handler('escapeHandler'); - - // doesn't seem to work correctly for attributes - $parser->set_option('XML_OPTION_ENTITIES_PARSED', 1); - - $parser->parse($string); - - return $this->tokens; - - } - - /** - * Open tag event handler, interface is defined by PEAR package. - */ - public function openHandler(&$parser, $name, $attrs, $closed) { - // entities are not resolved in attrs - foreach ($attrs as $key => $attr) { - $attrs[$key] = $this->parseData($attr); - } - if ($closed) { - $this->tokens[] = new HTMLPurifier_Token_Empty($name, $attrs); - } else { - $this->tokens[] = new HTMLPurifier_Token_Start($name, $attrs); - } - return true; - } - - /** - * Close tag event handler, interface is defined by PEAR package. - */ - public function closeHandler(&$parser, $name) { - // HTMLSax3 seems to always send empty tags an extra close tag - // check and ignore if you see it: - // [TESTME] to make sure it doesn't overreach - if ($this->tokens[count($this->tokens)-1] instanceof HTMLPurifier_Token_Empty) { - return true; - } - $this->tokens[] = new HTMLPurifier_Token_End($name); - return true; - } - - /** - * Data event handler, interface is defined by PEAR package. - */ - public function dataHandler(&$parser, $data) { - $this->tokens[] = new HTMLPurifier_Token_Text($data); - return true; - } - - /** - * Escaped text handler, interface is defined by PEAR package. - */ - public function escapeHandler(&$parser, $data) { - if (strpos($data, '--') === 0) { - $this->tokens[] = new HTMLPurifier_Token_Comment($data); - } - // CDATA is handled elsewhere, but if it was handled here: - //if (strpos($data, '[CDATA[') === 0) { - // $this->tokens[] = new HTMLPurifier_Token_Text( - // substr($data, 7, strlen($data) - 9) ); - //} - return true; - } - -} - -// vim: et sw=4 sts=4 diff --git a/modules/gallery/lib/HTMLPurifier/HTMLPurifier/Lexer/PH5P.php b/modules/gallery/lib/HTMLPurifier/HTMLPurifier/Lexer/PH5P.php deleted file mode 100644 index 0d20c0ce..00000000 --- a/modules/gallery/lib/HTMLPurifier/HTMLPurifier/Lexer/PH5P.php +++ /dev/null @@ -1,3906 +0,0 @@ -normalize($html, $config, $context); - $new_html = $this->wrapHTML($new_html, $config, $context); - try { - $parser = new HTML5($new_html); - $doc = $parser->save(); - } catch (DOMException $e) { - // Uh oh, it failed. Punt to DirectLex. - $lexer = new HTMLPurifier_Lexer_DirectLex(); - $context->register('PH5PError', $e); // save the error, so we can detect it - return $lexer->tokenizeHTML($html, $config, $context); // use original HTML - } - $tokens = array(); - $this->tokenizeDOM( - $doc->getElementsByTagName('html')->item(0)-> // - getElementsByTagName('body')->item(0)-> // - getElementsByTagName('div')->item(0) //
                - , $tokens); - return $tokens; - } - -} - -/* - -Copyright 2007 Jeroen van der Meer - -Permission is hereby granted, free of charge, to any person obtaining a -copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be included -in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, -TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE -SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -*/ - -class HTML5 { - private $data; - private $char; - private $EOF; - private $state; - private $tree; - private $token; - private $content_model; - private $escape = false; - private $entities = array('AElig;','AElig','AMP;','AMP','Aacute;','Aacute', - 'Acirc;','Acirc','Agrave;','Agrave','Alpha;','Aring;','Aring','Atilde;', - 'Atilde','Auml;','Auml','Beta;','COPY;','COPY','Ccedil;','Ccedil','Chi;', - 'Dagger;','Delta;','ETH;','ETH','Eacute;','Eacute','Ecirc;','Ecirc','Egrave;', - 'Egrave','Epsilon;','Eta;','Euml;','Euml','GT;','GT','Gamma;','Iacute;', - 'Iacute','Icirc;','Icirc','Igrave;','Igrave','Iota;','Iuml;','Iuml','Kappa;', - 'LT;','LT','Lambda;','Mu;','Ntilde;','Ntilde','Nu;','OElig;','Oacute;', - 'Oacute','Ocirc;','Ocirc','Ograve;','Ograve','Omega;','Omicron;','Oslash;', - 'Oslash','Otilde;','Otilde','Ouml;','Ouml','Phi;','Pi;','Prime;','Psi;', - 'QUOT;','QUOT','REG;','REG','Rho;','Scaron;','Sigma;','THORN;','THORN', - 'TRADE;','Tau;','Theta;','Uacute;','Uacute','Ucirc;','Ucirc','Ugrave;', - 'Ugrave','Upsilon;','Uuml;','Uuml','Xi;','Yacute;','Yacute','Yuml;','Zeta;', - 'aacute;','aacute','acirc;','acirc','acute;','acute','aelig;','aelig', - 'agrave;','agrave','alefsym;','alpha;','amp;','amp','and;','ang;','apos;', - 'aring;','aring','asymp;','atilde;','atilde','auml;','auml','bdquo;','beta;', - 'brvbar;','brvbar','bull;','cap;','ccedil;','ccedil','cedil;','cedil', - 'cent;','cent','chi;','circ;','clubs;','cong;','copy;','copy','crarr;', - 'cup;','curren;','curren','dArr;','dagger;','darr;','deg;','deg','delta;', - 'diams;','divide;','divide','eacute;','eacute','ecirc;','ecirc','egrave;', - 'egrave','empty;','emsp;','ensp;','epsilon;','equiv;','eta;','eth;','eth', - 'euml;','euml','euro;','exist;','fnof;','forall;','frac12;','frac12', - 'frac14;','frac14','frac34;','frac34','frasl;','gamma;','ge;','gt;','gt', - 'hArr;','harr;','hearts;','hellip;','iacute;','iacute','icirc;','icirc', - 'iexcl;','iexcl','igrave;','igrave','image;','infin;','int;','iota;', - 'iquest;','iquest','isin;','iuml;','iuml','kappa;','lArr;','lambda;','lang;', - 'laquo;','laquo','larr;','lceil;','ldquo;','le;','lfloor;','lowast;','loz;', - 'lrm;','lsaquo;','lsquo;','lt;','lt','macr;','macr','mdash;','micro;','micro', - 'middot;','middot','minus;','mu;','nabla;','nbsp;','nbsp','ndash;','ne;', - 'ni;','not;','not','notin;','nsub;','ntilde;','ntilde','nu;','oacute;', - 'oacute','ocirc;','ocirc','oelig;','ograve;','ograve','oline;','omega;', - 'omicron;','oplus;','or;','ordf;','ordf','ordm;','ordm','oslash;','oslash', - 'otilde;','otilde','otimes;','ouml;','ouml','para;','para','part;','permil;', - 'perp;','phi;','pi;','piv;','plusmn;','plusmn','pound;','pound','prime;', - 'prod;','prop;','psi;','quot;','quot','rArr;','radic;','rang;','raquo;', - 'raquo','rarr;','rceil;','rdquo;','real;','reg;','reg','rfloor;','rho;', - 'rlm;','rsaquo;','rsquo;','sbquo;','scaron;','sdot;','sect;','sect','shy;', - 'shy','sigma;','sigmaf;','sim;','spades;','sub;','sube;','sum;','sup1;', - 'sup1','sup2;','sup2','sup3;','sup3','sup;','supe;','szlig;','szlig','tau;', - 'there4;','theta;','thetasym;','thinsp;','thorn;','thorn','tilde;','times;', - 'times','trade;','uArr;','uacute;','uacute','uarr;','ucirc;','ucirc', - 'ugrave;','ugrave','uml;','uml','upsih;','upsilon;','uuml;','uuml','weierp;', - 'xi;','yacute;','yacute','yen;','yen','yuml;','yuml','zeta;','zwj;','zwnj;'); - - const PCDATA = 0; - const RCDATA = 1; - const CDATA = 2; - const PLAINTEXT = 3; - - const DOCTYPE = 0; - const STARTTAG = 1; - const ENDTAG = 2; - const COMMENT = 3; - const CHARACTR = 4; - const EOF = 5; - - public function __construct($data) { - $data = str_replace("\r\n", "\n", $data); - $data = str_replace("\r", null, $data); - - $this->data = $data; - $this->char = -1; - $this->EOF = strlen($data); - $this->tree = new HTML5TreeConstructer; - $this->content_model = self::PCDATA; - - $this->state = 'data'; - - while($this->state !== null) { - $this->{$this->state.'State'}(); - } - } - - public function save() { - return $this->tree->save(); - } - - private function char() { - return ($this->char < $this->EOF) - ? $this->data[$this->char] - : false; - } - - private function character($s, $l = 0) { - if($s + $l < $this->EOF) { - if($l === 0) { - return $this->data[$s]; - } else { - return substr($this->data, $s, $l); - } - } - } - - private function characters($char_class, $start) { - return preg_replace('#^(['.$char_class.']+).*#s', '\\1', substr($this->data, $start)); - } - - private function dataState() { - // Consume the next input character - $this->char++; - $char = $this->char(); - - if($char === '&' && ($this->content_model === self::PCDATA || $this->content_model === self::RCDATA)) { - /* U+0026 AMPERSAND (&) - When the content model flag is set to one of the PCDATA or RCDATA - states: switch to the entity data state. Otherwise: treat it as per - the "anything else" entry below. */ - $this->state = 'entityData'; - - } elseif($char === '-') { - /* If the content model flag is set to either the RCDATA state or - the CDATA state, and the escape flag is false, and there are at - least three characters before this one in the input stream, and the - last four characters in the input stream, including this one, are - U+003C LESS-THAN SIGN, U+0021 EXCLAMATION MARK, U+002D HYPHEN-MINUS, - and U+002D HYPHEN-MINUS (""), - set the escape flag to false. */ - if(($this->content_model === self::RCDATA || - $this->content_model === self::CDATA) && $this->escape === true && - $this->character($this->char, 3) === '-->') { - $this->escape = false; - } - - /* In any case, emit the input character as a character token. - Stay in the data state. */ - $this->emitToken(array( - 'type' => self::CHARACTR, - 'data' => $char - )); - - } elseif($this->char === $this->EOF) { - /* EOF - Emit an end-of-file token. */ - $this->EOF(); - - } elseif($this->content_model === self::PLAINTEXT) { - /* When the content model flag is set to the PLAINTEXT state - THIS DIFFERS GREATLY FROM THE SPEC: Get the remaining characters of - the text and emit it as a character token. */ - $this->emitToken(array( - 'type' => self::CHARACTR, - 'data' => substr($this->data, $this->char) - )); - - $this->EOF(); - - } else { - /* Anything else - THIS DIFFERS GREATLY FROM THE SPEC: Get as many character that - otherwise would also be treated as a character token and emit it - as a single character token. Stay in the data state. */ - $len = strcspn($this->data, '<&', $this->char); - $char = substr($this->data, $this->char, $len); - $this->char += $len - 1; - - $this->emitToken(array( - 'type' => self::CHARACTR, - 'data' => $char - )); - - $this->state = 'data'; - } - } - - private function entityDataState() { - // Attempt to consume an entity. - $entity = $this->entity(); - - // If nothing is returned, emit a U+0026 AMPERSAND character token. - // Otherwise, emit the character token that was returned. - $char = (!$entity) ? '&' : $entity; - $this->emitToken(array( - 'type' => self::CHARACTR, - 'data' => $char - )); - - // Finally, switch to the data state. - $this->state = 'data'; - } - - private function tagOpenState() { - switch($this->content_model) { - case self::RCDATA: - case self::CDATA: - /* If the next input character is a U+002F SOLIDUS (/) character, - consume it and switch to the close tag open state. If the next - input character is not a U+002F SOLIDUS (/) character, emit a - U+003C LESS-THAN SIGN character token and switch to the data - state to process the next input character. */ - if($this->character($this->char + 1) === '/') { - $this->char++; - $this->state = 'closeTagOpen'; - - } else { - $this->emitToken(array( - 'type' => self::CHARACTR, - 'data' => '<' - )); - - $this->state = 'data'; - } - break; - - case self::PCDATA: - // If the content model flag is set to the PCDATA state - // Consume the next input character: - $this->char++; - $char = $this->char(); - - if($char === '!') { - /* U+0021 EXCLAMATION MARK (!) - Switch to the markup declaration open state. */ - $this->state = 'markupDeclarationOpen'; - - } elseif($char === '/') { - /* U+002F SOLIDUS (/) - Switch to the close tag open state. */ - $this->state = 'closeTagOpen'; - - } elseif(preg_match('/^[A-Za-z]$/', $char)) { - /* U+0041 LATIN LETTER A through to U+005A LATIN LETTER Z - Create a new start tag token, set its tag name to the lowercase - version of the input character (add 0x0020 to the character's code - point), then switch to the tag name state. (Don't emit the token - yet; further details will be filled in before it is emitted.) */ - $this->token = array( - 'name' => strtolower($char), - 'type' => self::STARTTAG, - 'attr' => array() - ); - - $this->state = 'tagName'; - - } elseif($char === '>') { - /* U+003E GREATER-THAN SIGN (>) - Parse error. Emit a U+003C LESS-THAN SIGN character token and a - U+003E GREATER-THAN SIGN character token. Switch to the data state. */ - $this->emitToken(array( - 'type' => self::CHARACTR, - 'data' => '<>' - )); - - $this->state = 'data'; - - } elseif($char === '?') { - /* U+003F QUESTION MARK (?) - Parse error. Switch to the bogus comment state. */ - $this->state = 'bogusComment'; - - } else { - /* Anything else - Parse error. Emit a U+003C LESS-THAN SIGN character token and - reconsume the current input character in the data state. */ - $this->emitToken(array( - 'type' => self::CHARACTR, - 'data' => '<' - )); - - $this->char--; - $this->state = 'data'; - } - break; - } - } - - private function closeTagOpenState() { - $next_node = strtolower($this->characters('A-Za-z', $this->char + 1)); - $the_same = count($this->tree->stack) > 0 && $next_node === end($this->tree->stack)->nodeName; - - if(($this->content_model === self::RCDATA || $this->content_model === self::CDATA) && - (!$the_same || ($the_same && (!preg_match('/[\t\n\x0b\x0c >\/]/', - $this->character($this->char + 1 + strlen($next_node))) || $this->EOF === $this->char)))) { - /* If the content model flag is set to the RCDATA or CDATA states then - examine the next few characters. If they do not match the tag name of - the last start tag token emitted (case insensitively), or if they do but - they are not immediately followed by one of the following characters: - * U+0009 CHARACTER TABULATION - * U+000A LINE FEED (LF) - * U+000B LINE TABULATION - * U+000C FORM FEED (FF) - * U+0020 SPACE - * U+003E GREATER-THAN SIGN (>) - * U+002F SOLIDUS (/) - * EOF - ...then there is a parse error. Emit a U+003C LESS-THAN SIGN character - token, a U+002F SOLIDUS character token, and switch to the data state - to process the next input character. */ - $this->emitToken(array( - 'type' => self::CHARACTR, - 'data' => 'state = 'data'; - - } else { - /* Otherwise, if the content model flag is set to the PCDATA state, - or if the next few characters do match that tag name, consume the - next input character: */ - $this->char++; - $char = $this->char(); - - if(preg_match('/^[A-Za-z]$/', $char)) { - /* U+0041 LATIN LETTER A through to U+005A LATIN LETTER Z - Create a new end tag token, set its tag name to the lowercase version - of the input character (add 0x0020 to the character's code point), then - switch to the tag name state. (Don't emit the token yet; further details - will be filled in before it is emitted.) */ - $this->token = array( - 'name' => strtolower($char), - 'type' => self::ENDTAG - ); - - $this->state = 'tagName'; - - } elseif($char === '>') { - /* U+003E GREATER-THAN SIGN (>) - Parse error. Switch to the data state. */ - $this->state = 'data'; - - } elseif($this->char === $this->EOF) { - /* EOF - Parse error. Emit a U+003C LESS-THAN SIGN character token and a U+002F - SOLIDUS character token. Reconsume the EOF character in the data state. */ - $this->emitToken(array( - 'type' => self::CHARACTR, - 'data' => 'char--; - $this->state = 'data'; - - } else { - /* Parse error. Switch to the bogus comment state. */ - $this->state = 'bogusComment'; - } - } - } - - private function tagNameState() { - // Consume the next input character: - $this->char++; - $char = $this->character($this->char); - - if(preg_match('/^[\t\n\x0b\x0c ]$/', $char)) { - /* U+0009 CHARACTER TABULATION - U+000A LINE FEED (LF) - U+000B LINE TABULATION - U+000C FORM FEED (FF) - U+0020 SPACE - Switch to the before attribute name state. */ - $this->state = 'beforeAttributeName'; - - } elseif($char === '>') { - /* U+003E GREATER-THAN SIGN (>) - Emit the current tag token. Switch to the data state. */ - $this->emitToken($this->token); - $this->state = 'data'; - - } elseif($this->char === $this->EOF) { - /* EOF - Parse error. Emit the current tag token. Reconsume the EOF - character in the data state. */ - $this->emitToken($this->token); - - $this->char--; - $this->state = 'data'; - - } elseif($char === '/') { - /* U+002F SOLIDUS (/) - Parse error unless this is a permitted slash. Switch to the before - attribute name state. */ - $this->state = 'beforeAttributeName'; - - } else { - /* Anything else - Append the current input character to the current tag token's tag name. - Stay in the tag name state. */ - $this->token['name'] .= strtolower($char); - $this->state = 'tagName'; - } - } - - private function beforeAttributeNameState() { - // Consume the next input character: - $this->char++; - $char = $this->character($this->char); - - if(preg_match('/^[\t\n\x0b\x0c ]$/', $char)) { - /* U+0009 CHARACTER TABULATION - U+000A LINE FEED (LF) - U+000B LINE TABULATION - U+000C FORM FEED (FF) - U+0020 SPACE - Stay in the before attribute name state. */ - $this->state = 'beforeAttributeName'; - - } elseif($char === '>') { - /* U+003E GREATER-THAN SIGN (>) - Emit the current tag token. Switch to the data state. */ - $this->emitToken($this->token); - $this->state = 'data'; - - } elseif($char === '/') { - /* U+002F SOLIDUS (/) - Parse error unless this is a permitted slash. Stay in the before - attribute name state. */ - $this->state = 'beforeAttributeName'; - - } elseif($this->char === $this->EOF) { - /* EOF - Parse error. Emit the current tag token. Reconsume the EOF - character in the data state. */ - $this->emitToken($this->token); - - $this->char--; - $this->state = 'data'; - - } else { - /* Anything else - Start a new attribute in the current tag token. Set that attribute's - name to the current input character, and its value to the empty string. - Switch to the attribute name state. */ - $this->token['attr'][] = array( - 'name' => strtolower($char), - 'value' => null - ); - - $this->state = 'attributeName'; - } - } - - private function attributeNameState() { - // Consume the next input character: - $this->char++; - $char = $this->character($this->char); - - if(preg_match('/^[\t\n\x0b\x0c ]$/', $char)) { - /* U+0009 CHARACTER TABULATION - U+000A LINE FEED (LF) - U+000B LINE TABULATION - U+000C FORM FEED (FF) - U+0020 SPACE - Stay in the before attribute name state. */ - $this->state = 'afterAttributeName'; - - } elseif($char === '=') { - /* U+003D EQUALS SIGN (=) - Switch to the before attribute value state. */ - $this->state = 'beforeAttributeValue'; - - } elseif($char === '>') { - /* U+003E GREATER-THAN SIGN (>) - Emit the current tag token. Switch to the data state. */ - $this->emitToken($this->token); - $this->state = 'data'; - - } elseif($char === '/' && $this->character($this->char + 1) !== '>') { - /* U+002F SOLIDUS (/) - Parse error unless this is a permitted slash. Switch to the before - attribute name state. */ - $this->state = 'beforeAttributeName'; - - } elseif($this->char === $this->EOF) { - /* EOF - Parse error. Emit the current tag token. Reconsume the EOF - character in the data state. */ - $this->emitToken($this->token); - - $this->char--; - $this->state = 'data'; - - } else { - /* Anything else - Append the current input character to the current attribute's name. - Stay in the attribute name state. */ - $last = count($this->token['attr']) - 1; - $this->token['attr'][$last]['name'] .= strtolower($char); - - $this->state = 'attributeName'; - } - } - - private function afterAttributeNameState() { - // Consume the next input character: - $this->char++; - $char = $this->character($this->char); - - if(preg_match('/^[\t\n\x0b\x0c ]$/', $char)) { - /* U+0009 CHARACTER TABULATION - U+000A LINE FEED (LF) - U+000B LINE TABULATION - U+000C FORM FEED (FF) - U+0020 SPACE - Stay in the after attribute name state. */ - $this->state = 'afterAttributeName'; - - } elseif($char === '=') { - /* U+003D EQUALS SIGN (=) - Switch to the before attribute value state. */ - $this->state = 'beforeAttributeValue'; - - } elseif($char === '>') { - /* U+003E GREATER-THAN SIGN (>) - Emit the current tag token. Switch to the data state. */ - $this->emitToken($this->token); - $this->state = 'data'; - - } elseif($char === '/' && $this->character($this->char + 1) !== '>') { - /* U+002F SOLIDUS (/) - Parse error unless this is a permitted slash. Switch to the - before attribute name state. */ - $this->state = 'beforeAttributeName'; - - } elseif($this->char === $this->EOF) { - /* EOF - Parse error. Emit the current tag token. Reconsume the EOF - character in the data state. */ - $this->emitToken($this->token); - - $this->char--; - $this->state = 'data'; - - } else { - /* Anything else - Start a new attribute in the current tag token. Set that attribute's - name to the current input character, and its value to the empty string. - Switch to the attribute name state. */ - $this->token['attr'][] = array( - 'name' => strtolower($char), - 'value' => null - ); - - $this->state = 'attributeName'; - } - } - - private function beforeAttributeValueState() { - // Consume the next input character: - $this->char++; - $char = $this->character($this->char); - - if(preg_match('/^[\t\n\x0b\x0c ]$/', $char)) { - /* U+0009 CHARACTER TABULATION - U+000A LINE FEED (LF) - U+000B LINE TABULATION - U+000C FORM FEED (FF) - U+0020 SPACE - Stay in the before attribute value state. */ - $this->state = 'beforeAttributeValue'; - - } elseif($char === '"') { - /* U+0022 QUOTATION MARK (") - Switch to the attribute value (double-quoted) state. */ - $this->state = 'attributeValueDoubleQuoted'; - - } elseif($char === '&') { - /* U+0026 AMPERSAND (&) - Switch to the attribute value (unquoted) state and reconsume - this input character. */ - $this->char--; - $this->state = 'attributeValueUnquoted'; - - } elseif($char === '\'') { - /* U+0027 APOSTROPHE (') - Switch to the attribute value (single-quoted) state. */ - $this->state = 'attributeValueSingleQuoted'; - - } elseif($char === '>') { - /* U+003E GREATER-THAN SIGN (>) - Emit the current tag token. Switch to the data state. */ - $this->emitToken($this->token); - $this->state = 'data'; - - } else { - /* Anything else - Append the current input character to the current attribute's value. - Switch to the attribute value (unquoted) state. */ - $last = count($this->token['attr']) - 1; - $this->token['attr'][$last]['value'] .= $char; - - $this->state = 'attributeValueUnquoted'; - } - } - - private function attributeValueDoubleQuotedState() { - // Consume the next input character: - $this->char++; - $char = $this->character($this->char); - - if($char === '"') { - /* U+0022 QUOTATION MARK (") - Switch to the before attribute name state. */ - $this->state = 'beforeAttributeName'; - - } elseif($char === '&') { - /* U+0026 AMPERSAND (&) - Switch to the entity in attribute value state. */ - $this->entityInAttributeValueState('double'); - - } elseif($this->char === $this->EOF) { - /* EOF - Parse error. Emit the current tag token. Reconsume the character - in the data state. */ - $this->emitToken($this->token); - - $this->char--; - $this->state = 'data'; - - } else { - /* Anything else - Append the current input character to the current attribute's value. - Stay in the attribute value (double-quoted) state. */ - $last = count($this->token['attr']) - 1; - $this->token['attr'][$last]['value'] .= $char; - - $this->state = 'attributeValueDoubleQuoted'; - } - } - - private function attributeValueSingleQuotedState() { - // Consume the next input character: - $this->char++; - $char = $this->character($this->char); - - if($char === '\'') { - /* U+0022 QUOTATION MARK (') - Switch to the before attribute name state. */ - $this->state = 'beforeAttributeName'; - - } elseif($char === '&') { - /* U+0026 AMPERSAND (&) - Switch to the entity in attribute value state. */ - $this->entityInAttributeValueState('single'); - - } elseif($this->char === $this->EOF) { - /* EOF - Parse error. Emit the current tag token. Reconsume the character - in the data state. */ - $this->emitToken($this->token); - - $this->char--; - $this->state = 'data'; - - } else { - /* Anything else - Append the current input character to the current attribute's value. - Stay in the attribute value (single-quoted) state. */ - $last = count($this->token['attr']) - 1; - $this->token['attr'][$last]['value'] .= $char; - - $this->state = 'attributeValueSingleQuoted'; - } - } - - private function attributeValueUnquotedState() { - // Consume the next input character: - $this->char++; - $char = $this->character($this->char); - - if(preg_match('/^[\t\n\x0b\x0c ]$/', $char)) { - /* U+0009 CHARACTER TABULATION - U+000A LINE FEED (LF) - U+000B LINE TABULATION - U+000C FORM FEED (FF) - U+0020 SPACE - Switch to the before attribute name state. */ - $this->state = 'beforeAttributeName'; - - } elseif($char === '&') { - /* U+0026 AMPERSAND (&) - Switch to the entity in attribute value state. */ - $this->entityInAttributeValueState(); - - } elseif($char === '>') { - /* U+003E GREATER-THAN SIGN (>) - Emit the current tag token. Switch to the data state. */ - $this->emitToken($this->token); - $this->state = 'data'; - - } else { - /* Anything else - Append the current input character to the current attribute's value. - Stay in the attribute value (unquoted) state. */ - $last = count($this->token['attr']) - 1; - $this->token['attr'][$last]['value'] .= $char; - - $this->state = 'attributeValueUnquoted'; - } - } - - private function entityInAttributeValueState() { - // Attempt to consume an entity. - $entity = $this->entity(); - - // If nothing is returned, append a U+0026 AMPERSAND character to the - // current attribute's value. Otherwise, emit the character token that - // was returned. - $char = (!$entity) - ? '&' - : $entity; - - $last = count($this->token['attr']) - 1; - $this->token['attr'][$last]['value'] .= $char; - } - - private function bogusCommentState() { - /* Consume every character up to the first U+003E GREATER-THAN SIGN - character (>) or the end of the file (EOF), whichever comes first. Emit - a comment token whose data is the concatenation of all the characters - starting from and including the character that caused the state machine - to switch into the bogus comment state, up to and including the last - consumed character before the U+003E character, if any, or up to the - end of the file otherwise. (If the comment was started by the end of - the file (EOF), the token is empty.) */ - $data = $this->characters('^>', $this->char); - $this->emitToken(array( - 'data' => $data, - 'type' => self::COMMENT - )); - - $this->char += strlen($data); - - /* Switch to the data state. */ - $this->state = 'data'; - - /* If the end of the file was reached, reconsume the EOF character. */ - if($this->char === $this->EOF) { - $this->char = $this->EOF - 1; - } - } - - private function markupDeclarationOpenState() { - /* If the next two characters are both U+002D HYPHEN-MINUS (-) - characters, consume those two characters, create a comment token whose - data is the empty string, and switch to the comment state. */ - if($this->character($this->char + 1, 2) === '--') { - $this->char += 2; - $this->state = 'comment'; - $this->token = array( - 'data' => null, - 'type' => self::COMMENT - ); - - /* Otherwise if the next seven chacacters are a case-insensitive match - for the word "DOCTYPE", then consume those characters and switch to the - DOCTYPE state. */ - } elseif(strtolower($this->character($this->char + 1, 7)) === 'doctype') { - $this->char += 7; - $this->state = 'doctype'; - - /* Otherwise, is is a parse error. Switch to the bogus comment state. - The next character that is consumed, if any, is the first character - that will be in the comment. */ - } else { - $this->char++; - $this->state = 'bogusComment'; - } - } - - private function commentState() { - /* Consume the next input character: */ - $this->char++; - $char = $this->char(); - - /* U+002D HYPHEN-MINUS (-) */ - if($char === '-') { - /* Switch to the comment dash state */ - $this->state = 'commentDash'; - - /* EOF */ - } elseif($this->char === $this->EOF) { - /* Parse error. Emit the comment token. Reconsume the EOF character - in the data state. */ - $this->emitToken($this->token); - $this->char--; - $this->state = 'data'; - - /* Anything else */ - } else { - /* Append the input character to the comment token's data. Stay in - the comment state. */ - $this->token['data'] .= $char; - } - } - - private function commentDashState() { - /* Consume the next input character: */ - $this->char++; - $char = $this->char(); - - /* U+002D HYPHEN-MINUS (-) */ - if($char === '-') { - /* Switch to the comment end state */ - $this->state = 'commentEnd'; - - /* EOF */ - } elseif($this->char === $this->EOF) { - /* Parse error. Emit the comment token. Reconsume the EOF character - in the data state. */ - $this->emitToken($this->token); - $this->char--; - $this->state = 'data'; - - /* Anything else */ - } else { - /* Append a U+002D HYPHEN-MINUS (-) character and the input - character to the comment token's data. Switch to the comment state. */ - $this->token['data'] .= '-'.$char; - $this->state = 'comment'; - } - } - - private function commentEndState() { - /* Consume the next input character: */ - $this->char++; - $char = $this->char(); - - if($char === '>') { - $this->emitToken($this->token); - $this->state = 'data'; - - } elseif($char === '-') { - $this->token['data'] .= '-'; - - } elseif($this->char === $this->EOF) { - $this->emitToken($this->token); - $this->char--; - $this->state = 'data'; - - } else { - $this->token['data'] .= '--'.$char; - $this->state = 'comment'; - } - } - - private function doctypeState() { - /* Consume the next input character: */ - $this->char++; - $char = $this->char(); - - if(preg_match('/^[\t\n\x0b\x0c ]$/', $char)) { - $this->state = 'beforeDoctypeName'; - - } else { - $this->char--; - $this->state = 'beforeDoctypeName'; - } - } - - private function beforeDoctypeNameState() { - /* Consume the next input character: */ - $this->char++; - $char = $this->char(); - - if(preg_match('/^[\t\n\x0b\x0c ]$/', $char)) { - // Stay in the before DOCTYPE name state. - - } elseif(preg_match('/^[a-z]$/', $char)) { - $this->token = array( - 'name' => strtoupper($char), - 'type' => self::DOCTYPE, - 'error' => true - ); - - $this->state = 'doctypeName'; - - } elseif($char === '>') { - $this->emitToken(array( - 'name' => null, - 'type' => self::DOCTYPE, - 'error' => true - )); - - $this->state = 'data'; - - } elseif($this->char === $this->EOF) { - $this->emitToken(array( - 'name' => null, - 'type' => self::DOCTYPE, - 'error' => true - )); - - $this->char--; - $this->state = 'data'; - - } else { - $this->token = array( - 'name' => $char, - 'type' => self::DOCTYPE, - 'error' => true - ); - - $this->state = 'doctypeName'; - } - } - - private function doctypeNameState() { - /* Consume the next input character: */ - $this->char++; - $char = $this->char(); - - if(preg_match('/^[\t\n\x0b\x0c ]$/', $char)) { - $this->state = 'AfterDoctypeName'; - - } elseif($char === '>') { - $this->emitToken($this->token); - $this->state = 'data'; - - } elseif(preg_match('/^[a-z]$/', $char)) { - $this->token['name'] .= strtoupper($char); - - } elseif($this->char === $this->EOF) { - $this->emitToken($this->token); - $this->char--; - $this->state = 'data'; - - } else { - $this->token['name'] .= $char; - } - - $this->token['error'] = ($this->token['name'] === 'HTML') - ? false - : true; - } - - private function afterDoctypeNameState() { - /* Consume the next input character: */ - $this->char++; - $char = $this->char(); - - if(preg_match('/^[\t\n\x0b\x0c ]$/', $char)) { - // Stay in the DOCTYPE name state. - - } elseif($char === '>') { - $this->emitToken($this->token); - $this->state = 'data'; - - } elseif($this->char === $this->EOF) { - $this->emitToken($this->token); - $this->char--; - $this->state = 'data'; - - } else { - $this->token['error'] = true; - $this->state = 'bogusDoctype'; - } - } - - private function bogusDoctypeState() { - /* Consume the next input character: */ - $this->char++; - $char = $this->char(); - - if($char === '>') { - $this->emitToken($this->token); - $this->state = 'data'; - - } elseif($this->char === $this->EOF) { - $this->emitToken($this->token); - $this->char--; - $this->state = 'data'; - - } else { - // Stay in the bogus DOCTYPE state. - } - } - - private function entity() { - $start = $this->char; - - // This section defines how to consume an entity. This definition is - // used when parsing entities in text and in attributes. - - // The behaviour depends on the identity of the next character (the - // one immediately after the U+0026 AMPERSAND character): - - switch($this->character($this->char + 1)) { - // U+0023 NUMBER SIGN (#) - case '#': - - // The behaviour further depends on the character after the - // U+0023 NUMBER SIGN: - switch($this->character($this->char + 1)) { - // U+0078 LATIN SMALL LETTER X - // U+0058 LATIN CAPITAL LETTER X - case 'x': - case 'X': - // Follow the steps below, but using the range of - // characters U+0030 DIGIT ZERO through to U+0039 DIGIT - // NINE, U+0061 LATIN SMALL LETTER A through to U+0066 - // LATIN SMALL LETTER F, and U+0041 LATIN CAPITAL LETTER - // A, through to U+0046 LATIN CAPITAL LETTER F (in other - // words, 0-9, A-F, a-f). - $char = 1; - $char_class = '0-9A-Fa-f'; - break; - - // Anything else - default: - // Follow the steps below, but using the range of - // characters U+0030 DIGIT ZERO through to U+0039 DIGIT - // NINE (i.e. just 0-9). - $char = 0; - $char_class = '0-9'; - break; - } - - // Consume as many characters as match the range of characters - // given above. - $this->char++; - $e_name = $this->characters($char_class, $this->char + $char + 1); - $entity = $this->character($start, $this->char); - $cond = strlen($e_name) > 0; - - // The rest of the parsing happens bellow. - break; - - // Anything else - default: - // Consume the maximum number of characters possible, with the - // consumed characters case-sensitively matching one of the - // identifiers in the first column of the entities table. - $e_name = $this->characters('0-9A-Za-z;', $this->char + 1); - $len = strlen($e_name); - - for($c = 1; $c <= $len; $c++) { - $id = substr($e_name, 0, $c); - $this->char++; - - if(in_array($id, $this->entities)) { - if ($e_name[$c-1] !== ';') { - if ($c < $len && $e_name[$c] == ';') { - $this->char++; // consume extra semicolon - } - } - $entity = $id; - break; - } - } - - $cond = isset($entity); - // The rest of the parsing happens bellow. - break; - } - - if(!$cond) { - // If no match can be made, then this is a parse error. No - // characters are consumed, and nothing is returned. - $this->char = $start; - return false; - } - - // Return a character token for the character corresponding to the - // entity name (as given by the second column of the entities table). - return html_entity_decode('&'.$entity.';', ENT_QUOTES, 'UTF-8'); - } - - private function emitToken($token) { - $emit = $this->tree->emitToken($token); - - if(is_int($emit)) { - $this->content_model = $emit; - - } elseif($token['type'] === self::ENDTAG) { - $this->content_model = self::PCDATA; - } - } - - private function EOF() { - $this->state = null; - $this->tree->emitToken(array( - 'type' => self::EOF - )); - } -} - -class HTML5TreeConstructer { - public $stack = array(); - - private $phase; - private $mode; - private $dom; - private $foster_parent = null; - private $a_formatting = array(); - - private $head_pointer = null; - private $form_pointer = null; - - private $scoping = array('button','caption','html','marquee','object','table','td','th'); - private $formatting = array('a','b','big','em','font','i','nobr','s','small','strike','strong','tt','u'); - private $special = array('address','area','base','basefont','bgsound', - 'blockquote','body','br','center','col','colgroup','dd','dir','div','dl', - 'dt','embed','fieldset','form','frame','frameset','h1','h2','h3','h4','h5', - 'h6','head','hr','iframe','image','img','input','isindex','li','link', - 'listing','menu','meta','noembed','noframes','noscript','ol','optgroup', - 'option','p','param','plaintext','pre','script','select','spacer','style', - 'tbody','textarea','tfoot','thead','title','tr','ul','wbr'); - - // The different phases. - const INIT_PHASE = 0; - const ROOT_PHASE = 1; - const MAIN_PHASE = 2; - const END_PHASE = 3; - - // The different insertion modes for the main phase. - const BEFOR_HEAD = 0; - const IN_HEAD = 1; - const AFTER_HEAD = 2; - const IN_BODY = 3; - const IN_TABLE = 4; - const IN_CAPTION = 5; - const IN_CGROUP = 6; - const IN_TBODY = 7; - const IN_ROW = 8; - const IN_CELL = 9; - const IN_SELECT = 10; - const AFTER_BODY = 11; - const IN_FRAME = 12; - const AFTR_FRAME = 13; - - // The different types of elements. - const SPECIAL = 0; - const SCOPING = 1; - const FORMATTING = 2; - const PHRASING = 3; - - const MARKER = 0; - - public function __construct() { - $this->phase = self::INIT_PHASE; - $this->mode = self::BEFOR_HEAD; - $this->dom = new DOMDocument; - - $this->dom->encoding = 'UTF-8'; - $this->dom->preserveWhiteSpace = true; - $this->dom->substituteEntities = true; - $this->dom->strictErrorChecking = false; - } - - // Process tag tokens - public function emitToken($token) { - switch($this->phase) { - case self::INIT_PHASE: return $this->initPhase($token); break; - case self::ROOT_PHASE: return $this->rootElementPhase($token); break; - case self::MAIN_PHASE: return $this->mainPhase($token); break; - case self::END_PHASE : return $this->trailingEndPhase($token); break; - } - } - - private function initPhase($token) { - /* Initially, the tree construction stage must handle each token - emitted from the tokenisation stage as follows: */ - - /* A DOCTYPE token that is marked as being in error - A comment token - A start tag token - An end tag token - A character token that is not one of one of U+0009 CHARACTER TABULATION, - U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED (FF), - or U+0020 SPACE - An end-of-file token */ - if((isset($token['error']) && $token['error']) || - $token['type'] === HTML5::COMMENT || - $token['type'] === HTML5::STARTTAG || - $token['type'] === HTML5::ENDTAG || - $token['type'] === HTML5::EOF || - ($token['type'] === HTML5::CHARACTR && isset($token['data']) && - !preg_match('/^[\t\n\x0b\x0c ]+$/', $token['data']))) { - /* This specification does not define how to handle this case. In - particular, user agents may ignore the entirety of this specification - altogether for such documents, and instead invoke special parse modes - with a greater emphasis on backwards compatibility. */ - - $this->phase = self::ROOT_PHASE; - return $this->rootElementPhase($token); - - /* A DOCTYPE token marked as being correct */ - } elseif(isset($token['error']) && !$token['error']) { - /* Append a DocumentType node to the Document node, with the name - attribute set to the name given in the DOCTYPE token (which will be - "HTML"), and the other attributes specific to DocumentType objects - set to null, empty lists, or the empty string as appropriate. */ - $doctype = new DOMDocumentType(null, null, 'HTML'); - - /* Then, switch to the root element phase of the tree construction - stage. */ - $this->phase = self::ROOT_PHASE; - - /* A character token that is one of one of U+0009 CHARACTER TABULATION, - U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED (FF), - or U+0020 SPACE */ - } elseif(isset($token['data']) && preg_match('/^[\t\n\x0b\x0c ]+$/', - $token['data'])) { - /* Append that character to the Document node. */ - $text = $this->dom->createTextNode($token['data']); - $this->dom->appendChild($text); - } - } - - private function rootElementPhase($token) { - /* After the initial phase, as each token is emitted from the tokenisation - stage, it must be processed as described in this section. */ - - /* A DOCTYPE token */ - if($token['type'] === HTML5::DOCTYPE) { - // Parse error. Ignore the token. - - /* A comment token */ - } elseif($token['type'] === HTML5::COMMENT) { - /* Append a Comment node to the Document object with the data - attribute set to the data given in the comment token. */ - $comment = $this->dom->createComment($token['data']); - $this->dom->appendChild($comment); - - /* A character token that is one of one of U+0009 CHARACTER TABULATION, - U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED (FF), - or U+0020 SPACE */ - } elseif($token['type'] === HTML5::CHARACTR && - preg_match('/^[\t\n\x0b\x0c ]+$/', $token['data'])) { - /* Append that character to the Document node. */ - $text = $this->dom->createTextNode($token['data']); - $this->dom->appendChild($text); - - /* A character token that is not one of U+0009 CHARACTER TABULATION, - U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED - (FF), or U+0020 SPACE - A start tag token - An end tag token - An end-of-file token */ - } elseif(($token['type'] === HTML5::CHARACTR && - !preg_match('/^[\t\n\x0b\x0c ]+$/', $token['data'])) || - $token['type'] === HTML5::STARTTAG || - $token['type'] === HTML5::ENDTAG || - $token['type'] === HTML5::EOF) { - /* Create an HTMLElement node with the tag name html, in the HTML - namespace. Append it to the Document object. Switch to the main - phase and reprocess the current token. */ - $html = $this->dom->createElement('html'); - $this->dom->appendChild($html); - $this->stack[] = $html; - - $this->phase = self::MAIN_PHASE; - return $this->mainPhase($token); - } - } - - private function mainPhase($token) { - /* Tokens in the main phase must be handled as follows: */ - - /* A DOCTYPE token */ - if($token['type'] === HTML5::DOCTYPE) { - // Parse error. Ignore the token. - - /* A start tag token with the tag name "html" */ - } elseif($token['type'] === HTML5::STARTTAG && $token['name'] === 'html') { - /* If this start tag token was not the first start tag token, then - it is a parse error. */ - - /* For each attribute on the token, check to see if the attribute - is already present on the top element of the stack of open elements. - If it is not, add the attribute and its corresponding value to that - element. */ - foreach($token['attr'] as $attr) { - if(!$this->stack[0]->hasAttribute($attr['name'])) { - $this->stack[0]->setAttribute($attr['name'], $attr['value']); - } - } - - /* An end-of-file token */ - } elseif($token['type'] === HTML5::EOF) { - /* Generate implied end tags. */ - $this->generateImpliedEndTags(); - - /* Anything else. */ - } else { - /* Depends on the insertion mode: */ - switch($this->mode) { - case self::BEFOR_HEAD: return $this->beforeHead($token); break; - case self::IN_HEAD: return $this->inHead($token); break; - case self::AFTER_HEAD: return $this->afterHead($token); break; - case self::IN_BODY: return $this->inBody($token); break; - case self::IN_TABLE: return $this->inTable($token); break; - case self::IN_CAPTION: return $this->inCaption($token); break; - case self::IN_CGROUP: return $this->inColumnGroup($token); break; - case self::IN_TBODY: return $this->inTableBody($token); break; - case self::IN_ROW: return $this->inRow($token); break; - case self::IN_CELL: return $this->inCell($token); break; - case self::IN_SELECT: return $this->inSelect($token); break; - case self::AFTER_BODY: return $this->afterBody($token); break; - case self::IN_FRAME: return $this->inFrameset($token); break; - case self::AFTR_FRAME: return $this->afterFrameset($token); break; - case self::END_PHASE: return $this->trailingEndPhase($token); break; - } - } - } - - private function beforeHead($token) { - /* Handle the token as follows: */ - - /* A character token that is one of one of U+0009 CHARACTER TABULATION, - U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED (FF), - or U+0020 SPACE */ - if($token['type'] === HTML5::CHARACTR && - preg_match('/^[\t\n\x0b\x0c ]+$/', $token['data'])) { - /* Append the character to the current node. */ - $this->insertText($token['data']); - - /* A comment token */ - } elseif($token['type'] === HTML5::COMMENT) { - /* Append a Comment node to the current node with the data attribute - set to the data given in the comment token. */ - $this->insertComment($token['data']); - - /* A start tag token with the tag name "head" */ - } elseif($token['type'] === HTML5::STARTTAG && $token['name'] === 'head') { - /* Create an element for the token, append the new element to the - current node and push it onto the stack of open elements. */ - $element = $this->insertElement($token); - - /* Set the head element pointer to this new element node. */ - $this->head_pointer = $element; - - /* Change the insertion mode to "in head". */ - $this->mode = self::IN_HEAD; - - /* A start tag token whose tag name is one of: "base", "link", "meta", - "script", "style", "title". Or an end tag with the tag name "html". - Or a character token that is not one of U+0009 CHARACTER TABULATION, - U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED (FF), - or U+0020 SPACE. Or any other start tag token */ - } elseif($token['type'] === HTML5::STARTTAG || - ($token['type'] === HTML5::ENDTAG && $token['name'] === 'html') || - ($token['type'] === HTML5::CHARACTR && !preg_match('/^[\t\n\x0b\x0c ]$/', - $token['data']))) { - /* Act as if a start tag token with the tag name "head" and no - attributes had been seen, then reprocess the current token. */ - $this->beforeHead(array( - 'name' => 'head', - 'type' => HTML5::STARTTAG, - 'attr' => array() - )); - - return $this->inHead($token); - - /* Any other end tag */ - } elseif($token['type'] === HTML5::ENDTAG) { - /* Parse error. Ignore the token. */ - } - } - - private function inHead($token) { - /* Handle the token as follows: */ - - /* A character token that is one of one of U+0009 CHARACTER TABULATION, - U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED (FF), - or U+0020 SPACE. - - THIS DIFFERS FROM THE SPEC: If the current node is either a title, style - or script element, append the character to the current node regardless - of its content. */ - if(($token['type'] === HTML5::CHARACTR && - preg_match('/^[\t\n\x0b\x0c ]+$/', $token['data'])) || ( - $token['type'] === HTML5::CHARACTR && in_array(end($this->stack)->nodeName, - array('title', 'style', 'script')))) { - /* Append the character to the current node. */ - $this->insertText($token['data']); - - /* A comment token */ - } elseif($token['type'] === HTML5::COMMENT) { - /* Append a Comment node to the current node with the data attribute - set to the data given in the comment token. */ - $this->insertComment($token['data']); - - } elseif($token['type'] === HTML5::ENDTAG && - in_array($token['name'], array('title', 'style', 'script'))) { - array_pop($this->stack); - return HTML5::PCDATA; - - /* A start tag with the tag name "title" */ - } elseif($token['type'] === HTML5::STARTTAG && $token['name'] === 'title') { - /* Create an element for the token and append the new element to the - node pointed to by the head element pointer, or, if that is null - (innerHTML case), to the current node. */ - if($this->head_pointer !== null) { - $element = $this->insertElement($token, false); - $this->head_pointer->appendChild($element); - - } else { - $element = $this->insertElement($token); - } - - /* Switch the tokeniser's content model flag to the RCDATA state. */ - return HTML5::RCDATA; - - /* A start tag with the tag name "style" */ - } elseif($token['type'] === HTML5::STARTTAG && $token['name'] === 'style') { - /* Create an element for the token and append the new element to the - node pointed to by the head element pointer, or, if that is null - (innerHTML case), to the current node. */ - if($this->head_pointer !== null) { - $element = $this->insertElement($token, false); - $this->head_pointer->appendChild($element); - - } else { - $this->insertElement($token); - } - - /* Switch the tokeniser's content model flag to the CDATA state. */ - return HTML5::CDATA; - - /* A start tag with the tag name "script" */ - } elseif($token['type'] === HTML5::STARTTAG && $token['name'] === 'script') { - /* Create an element for the token. */ - $element = $this->insertElement($token, false); - $this->head_pointer->appendChild($element); - - /* Switch the tokeniser's content model flag to the CDATA state. */ - return HTML5::CDATA; - - /* A start tag with the tag name "base", "link", or "meta" */ - } elseif($token['type'] === HTML5::STARTTAG && in_array($token['name'], - array('base', 'link', 'meta'))) { - /* Create an element for the token and append the new element to the - node pointed to by the head element pointer, or, if that is null - (innerHTML case), to the current node. */ - if($this->head_pointer !== null) { - $element = $this->insertElement($token, false); - $this->head_pointer->appendChild($element); - array_pop($this->stack); - - } else { - $this->insertElement($token); - } - - /* An end tag with the tag name "head" */ - } elseif($token['type'] === HTML5::ENDTAG && $token['name'] === 'head') { - /* If the current node is a head element, pop the current node off - the stack of open elements. */ - if($this->head_pointer->isSameNode(end($this->stack))) { - array_pop($this->stack); - - /* Otherwise, this is a parse error. */ - } else { - // k - } - - /* Change the insertion mode to "after head". */ - $this->mode = self::AFTER_HEAD; - - /* A start tag with the tag name "head" or an end tag except "html". */ - } elseif(($token['type'] === HTML5::STARTTAG && $token['name'] === 'head') || - ($token['type'] === HTML5::ENDTAG && $token['name'] !== 'html')) { - // Parse error. Ignore the token. - - /* Anything else */ - } else { - /* If the current node is a head element, act as if an end tag - token with the tag name "head" had been seen. */ - if($this->head_pointer->isSameNode(end($this->stack))) { - $this->inHead(array( - 'name' => 'head', - 'type' => HTML5::ENDTAG - )); - - /* Otherwise, change the insertion mode to "after head". */ - } else { - $this->mode = self::AFTER_HEAD; - } - - /* Then, reprocess the current token. */ - return $this->afterHead($token); - } - } - - private function afterHead($token) { - /* Handle the token as follows: */ - - /* A character token that is one of one of U+0009 CHARACTER TABULATION, - U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED (FF), - or U+0020 SPACE */ - if($token['type'] === HTML5::CHARACTR && - preg_match('/^[\t\n\x0b\x0c ]+$/', $token['data'])) { - /* Append the character to the current node. */ - $this->insertText($token['data']); - - /* A comment token */ - } elseif($token['type'] === HTML5::COMMENT) { - /* Append a Comment node to the current node with the data attribute - set to the data given in the comment token. */ - $this->insertComment($token['data']); - - /* A start tag token with the tag name "body" */ - } elseif($token['type'] === HTML5::STARTTAG && $token['name'] === 'body') { - /* Insert a body element for the token. */ - $this->insertElement($token); - - /* Change the insertion mode to "in body". */ - $this->mode = self::IN_BODY; - - /* A start tag token with the tag name "frameset" */ - } elseif($token['type'] === HTML5::STARTTAG && $token['name'] === 'frameset') { - /* Insert a frameset element for the token. */ - $this->insertElement($token); - - /* Change the insertion mode to "in frameset". */ - $this->mode = self::IN_FRAME; - - /* A start tag token whose tag name is one of: "base", "link", "meta", - "script", "style", "title" */ - } elseif($token['type'] === HTML5::STARTTAG && in_array($token['name'], - array('base', 'link', 'meta', 'script', 'style', 'title'))) { - /* Parse error. Switch the insertion mode back to "in head" and - reprocess the token. */ - $this->mode = self::IN_HEAD; - return $this->inHead($token); - - /* Anything else */ - } else { - /* Act as if a start tag token with the tag name "body" and no - attributes had been seen, and then reprocess the current token. */ - $this->afterHead(array( - 'name' => 'body', - 'type' => HTML5::STARTTAG, - 'attr' => array() - )); - - return $this->inBody($token); - } - } - - private function inBody($token) { - /* Handle the token as follows: */ - - switch($token['type']) { - /* A character token */ - case HTML5::CHARACTR: - /* Reconstruct the active formatting elements, if any. */ - $this->reconstructActiveFormattingElements(); - - /* Append the token's character to the current node. */ - $this->insertText($token['data']); - break; - - /* A comment token */ - case HTML5::COMMENT: - /* Append a Comment node to the current node with the data - attribute set to the data given in the comment token. */ - $this->insertComment($token['data']); - break; - - case HTML5::STARTTAG: - switch($token['name']) { - /* A start tag token whose tag name is one of: "script", - "style" */ - case 'script': case 'style': - /* Process the token as if the insertion mode had been "in - head". */ - return $this->inHead($token); - break; - - /* A start tag token whose tag name is one of: "base", "link", - "meta", "title" */ - case 'base': case 'link': case 'meta': case 'title': - /* Parse error. Process the token as if the insertion mode - had been "in head". */ - return $this->inHead($token); - break; - - /* A start tag token with the tag name "body" */ - case 'body': - /* Parse error. If the second element on the stack of open - elements is not a body element, or, if the stack of open - elements has only one node on it, then ignore the token. - (innerHTML case) */ - if(count($this->stack) === 1 || $this->stack[1]->nodeName !== 'body') { - // Ignore - - /* Otherwise, for each attribute on the token, check to see - if the attribute is already present on the body element (the - second element) on the stack of open elements. If it is not, - add the attribute and its corresponding value to that - element. */ - } else { - foreach($token['attr'] as $attr) { - if(!$this->stack[1]->hasAttribute($attr['name'])) { - $this->stack[1]->setAttribute($attr['name'], $attr['value']); - } - } - } - break; - - /* A start tag whose tag name is one of: "address", - "blockquote", "center", "dir", "div", "dl", "fieldset", - "listing", "menu", "ol", "p", "ul" */ - case 'address': case 'blockquote': case 'center': case 'dir': - case 'div': case 'dl': case 'fieldset': case 'listing': - case 'menu': case 'ol': case 'p': case 'ul': - /* If the stack of open elements has a p element in scope, - then act as if an end tag with the tag name p had been - seen. */ - if($this->elementInScope('p')) { - $this->emitToken(array( - 'name' => 'p', - 'type' => HTML5::ENDTAG - )); - } - - /* Insert an HTML element for the token. */ - $this->insertElement($token); - break; - - /* A start tag whose tag name is "form" */ - case 'form': - /* If the form element pointer is not null, ignore the - token with a parse error. */ - if($this->form_pointer !== null) { - // Ignore. - - /* Otherwise: */ - } else { - /* If the stack of open elements has a p element in - scope, then act as if an end tag with the tag name p - had been seen. */ - if($this->elementInScope('p')) { - $this->emitToken(array( - 'name' => 'p', - 'type' => HTML5::ENDTAG - )); - } - - /* Insert an HTML element for the token, and set the - form element pointer to point to the element created. */ - $element = $this->insertElement($token); - $this->form_pointer = $element; - } - break; - - /* A start tag whose tag name is "li", "dd" or "dt" */ - case 'li': case 'dd': case 'dt': - /* If the stack of open elements has a p element in scope, - then act as if an end tag with the tag name p had been - seen. */ - if($this->elementInScope('p')) { - $this->emitToken(array( - 'name' => 'p', - 'type' => HTML5::ENDTAG - )); - } - - $stack_length = count($this->stack) - 1; - - for($n = $stack_length; 0 <= $n; $n--) { - /* 1. Initialise node to be the current node (the - bottommost node of the stack). */ - $stop = false; - $node = $this->stack[$n]; - $cat = $this->getElementCategory($node->tagName); - - /* 2. If node is an li, dd or dt element, then pop all - the nodes from the current node up to node, including - node, then stop this algorithm. */ - if($token['name'] === $node->tagName || ($token['name'] !== 'li' - && ($node->tagName === 'dd' || $node->tagName === 'dt'))) { - for($x = $stack_length; $x >= $n ; $x--) { - array_pop($this->stack); - } - - break; - } - - /* 3. If node is not in the formatting category, and is - not in the phrasing category, and is not an address or - div element, then stop this algorithm. */ - if($cat !== self::FORMATTING && $cat !== self::PHRASING && - $node->tagName !== 'address' && $node->tagName !== 'div') { - break; - } - } - - /* Finally, insert an HTML element with the same tag - name as the token's. */ - $this->insertElement($token); - break; - - /* A start tag token whose tag name is "plaintext" */ - case 'plaintext': - /* If the stack of open elements has a p element in scope, - then act as if an end tag with the tag name p had been - seen. */ - if($this->elementInScope('p')) { - $this->emitToken(array( - 'name' => 'p', - 'type' => HTML5::ENDTAG - )); - } - - /* Insert an HTML element for the token. */ - $this->insertElement($token); - - return HTML5::PLAINTEXT; - break; - - /* A start tag whose tag name is one of: "h1", "h2", "h3", "h4", - "h5", "h6" */ - case 'h1': case 'h2': case 'h3': case 'h4': case 'h5': case 'h6': - /* If the stack of open elements has a p element in scope, - then act as if an end tag with the tag name p had been seen. */ - if($this->elementInScope('p')) { - $this->emitToken(array( - 'name' => 'p', - 'type' => HTML5::ENDTAG - )); - } - - /* If the stack of open elements has in scope an element whose - tag name is one of "h1", "h2", "h3", "h4", "h5", or "h6", then - this is a parse error; pop elements from the stack until an - element with one of those tag names has been popped from the - stack. */ - while($this->elementInScope(array('h1', 'h2', 'h3', 'h4', 'h5', 'h6'))) { - array_pop($this->stack); - } - - /* Insert an HTML element for the token. */ - $this->insertElement($token); - break; - - /* A start tag whose tag name is "a" */ - case 'a': - /* If the list of active formatting elements contains - an element whose tag name is "a" between the end of the - list and the last marker on the list (or the start of - the list if there is no marker on the list), then this - is a parse error; act as if an end tag with the tag name - "a" had been seen, then remove that element from the list - of active formatting elements and the stack of open - elements if the end tag didn't already remove it (it - might not have if the element is not in table scope). */ - $leng = count($this->a_formatting); - - for($n = $leng - 1; $n >= 0; $n--) { - if($this->a_formatting[$n] === self::MARKER) { - break; - - } elseif($this->a_formatting[$n]->nodeName === 'a') { - $this->emitToken(array( - 'name' => 'a', - 'type' => HTML5::ENDTAG - )); - break; - } - } - - /* Reconstruct the active formatting elements, if any. */ - $this->reconstructActiveFormattingElements(); - - /* Insert an HTML element for the token. */ - $el = $this->insertElement($token); - - /* Add that element to the list of active formatting - elements. */ - $this->a_formatting[] = $el; - break; - - /* A start tag whose tag name is one of: "b", "big", "em", "font", - "i", "nobr", "s", "small", "strike", "strong", "tt", "u" */ - case 'b': case 'big': case 'em': case 'font': case 'i': - case 'nobr': case 's': case 'small': case 'strike': - case 'strong': case 'tt': case 'u': - /* Reconstruct the active formatting elements, if any. */ - $this->reconstructActiveFormattingElements(); - - /* Insert an HTML element for the token. */ - $el = $this->insertElement($token); - - /* Add that element to the list of active formatting - elements. */ - $this->a_formatting[] = $el; - break; - - /* A start tag token whose tag name is "button" */ - case 'button': - /* If the stack of open elements has a button element in scope, - then this is a parse error; act as if an end tag with the tag - name "button" had been seen, then reprocess the token. (We don't - do that. Unnecessary.) */ - if($this->elementInScope('button')) { - $this->inBody(array( - 'name' => 'button', - 'type' => HTML5::ENDTAG - )); - } - - /* Reconstruct the active formatting elements, if any. */ - $this->reconstructActiveFormattingElements(); - - /* Insert an HTML element for the token. */ - $this->insertElement($token); - - /* Insert a marker at the end of the list of active - formatting elements. */ - $this->a_formatting[] = self::MARKER; - break; - - /* A start tag token whose tag name is one of: "marquee", "object" */ - case 'marquee': case 'object': - /* Reconstruct the active formatting elements, if any. */ - $this->reconstructActiveFormattingElements(); - - /* Insert an HTML element for the token. */ - $this->insertElement($token); - - /* Insert a marker at the end of the list of active - formatting elements. */ - $this->a_formatting[] = self::MARKER; - break; - - /* A start tag token whose tag name is "xmp" */ - case 'xmp': - /* Reconstruct the active formatting elements, if any. */ - $this->reconstructActiveFormattingElements(); - - /* Insert an HTML element for the token. */ - $this->insertElement($token); - - /* Switch the content model flag to the CDATA state. */ - return HTML5::CDATA; - break; - - /* A start tag whose tag name is "table" */ - case 'table': - /* If the stack of open elements has a p element in scope, - then act as if an end tag with the tag name p had been seen. */ - if($this->elementInScope('p')) { - $this->emitToken(array( - 'name' => 'p', - 'type' => HTML5::ENDTAG - )); - } - - /* Insert an HTML element for the token. */ - $this->insertElement($token); - - /* Change the insertion mode to "in table". */ - $this->mode = self::IN_TABLE; - break; - - /* A start tag whose tag name is one of: "area", "basefont", - "bgsound", "br", "embed", "img", "param", "spacer", "wbr" */ - case 'area': case 'basefont': case 'bgsound': case 'br': - case 'embed': case 'img': case 'param': case 'spacer': - case 'wbr': - /* Reconstruct the active formatting elements, if any. */ - $this->reconstructActiveFormattingElements(); - - /* Insert an HTML element for the token. */ - $this->insertElement($token); - - /* Immediately pop the current node off the stack of open elements. */ - array_pop($this->stack); - break; - - /* A start tag whose tag name is "hr" */ - case 'hr': - /* If the stack of open elements has a p element in scope, - then act as if an end tag with the tag name p had been seen. */ - if($this->elementInScope('p')) { - $this->emitToken(array( - 'name' => 'p', - 'type' => HTML5::ENDTAG - )); - } - - /* Insert an HTML element for the token. */ - $this->insertElement($token); - - /* Immediately pop the current node off the stack of open elements. */ - array_pop($this->stack); - break; - - /* A start tag whose tag name is "image" */ - case 'image': - /* Parse error. Change the token's tag name to "img" and - reprocess it. (Don't ask.) */ - $token['name'] = 'img'; - return $this->inBody($token); - break; - - /* A start tag whose tag name is "input" */ - case 'input': - /* Reconstruct the active formatting elements, if any. */ - $this->reconstructActiveFormattingElements(); - - /* Insert an input element for the token. */ - $element = $this->insertElement($token, false); - - /* If the form element pointer is not null, then associate the - input element with the form element pointed to by the form - element pointer. */ - $this->form_pointer !== null - ? $this->form_pointer->appendChild($element) - : end($this->stack)->appendChild($element); - - /* Pop that input element off the stack of open elements. */ - array_pop($this->stack); - break; - - /* A start tag whose tag name is "isindex" */ - case 'isindex': - /* Parse error. */ - // w/e - - /* If the form element pointer is not null, - then ignore the token. */ - if($this->form_pointer === null) { - /* Act as if a start tag token with the tag name "form" had - been seen. */ - $this->inBody(array( - 'name' => 'body', - 'type' => HTML5::STARTTAG, - 'attr' => array() - )); - - /* Act as if a start tag token with the tag name "hr" had - been seen. */ - $this->inBody(array( - 'name' => 'hr', - 'type' => HTML5::STARTTAG, - 'attr' => array() - )); - - /* Act as if a start tag token with the tag name "p" had - been seen. */ - $this->inBody(array( - 'name' => 'p', - 'type' => HTML5::STARTTAG, - 'attr' => array() - )); - - /* Act as if a start tag token with the tag name "label" - had been seen. */ - $this->inBody(array( - 'name' => 'label', - 'type' => HTML5::STARTTAG, - 'attr' => array() - )); - - /* Act as if a stream of character tokens had been seen. */ - $this->insertText('This is a searchable index. '. - 'Insert your search keywords here: '); - - /* Act as if a start tag token with the tag name "input" - had been seen, with all the attributes from the "isindex" - token, except with the "name" attribute set to the value - "isindex" (ignoring any explicit "name" attribute). */ - $attr = $token['attr']; - $attr[] = array('name' => 'name', 'value' => 'isindex'); - - $this->inBody(array( - 'name' => 'input', - 'type' => HTML5::STARTTAG, - 'attr' => $attr - )); - - /* Act as if a stream of character tokens had been seen - (see below for what they should say). */ - $this->insertText('This is a searchable index. '. - 'Insert your search keywords here: '); - - /* Act as if an end tag token with the tag name "label" - had been seen. */ - $this->inBody(array( - 'name' => 'label', - 'type' => HTML5::ENDTAG - )); - - /* Act as if an end tag token with the tag name "p" had - been seen. */ - $this->inBody(array( - 'name' => 'p', - 'type' => HTML5::ENDTAG - )); - - /* Act as if a start tag token with the tag name "hr" had - been seen. */ - $this->inBody(array( - 'name' => 'hr', - 'type' => HTML5::ENDTAG - )); - - /* Act as if an end tag token with the tag name "form" had - been seen. */ - $this->inBody(array( - 'name' => 'form', - 'type' => HTML5::ENDTAG - )); - } - break; - - /* A start tag whose tag name is "textarea" */ - case 'textarea': - $this->insertElement($token); - - /* Switch the tokeniser's content model flag to the - RCDATA state. */ - return HTML5::RCDATA; - break; - - /* A start tag whose tag name is one of: "iframe", "noembed", - "noframes" */ - case 'iframe': case 'noembed': case 'noframes': - $this->insertElement($token); - - /* Switch the tokeniser's content model flag to the CDATA state. */ - return HTML5::CDATA; - break; - - /* A start tag whose tag name is "select" */ - case 'select': - /* Reconstruct the active formatting elements, if any. */ - $this->reconstructActiveFormattingElements(); - - /* Insert an HTML element for the token. */ - $this->insertElement($token); - - /* Change the insertion mode to "in select". */ - $this->mode = self::IN_SELECT; - break; - - /* A start or end tag whose tag name is one of: "caption", "col", - "colgroup", "frame", "frameset", "head", "option", "optgroup", - "tbody", "td", "tfoot", "th", "thead", "tr". */ - case 'caption': case 'col': case 'colgroup': case 'frame': - case 'frameset': case 'head': case 'option': case 'optgroup': - case 'tbody': case 'td': case 'tfoot': case 'th': case 'thead': - case 'tr': - // Parse error. Ignore the token. - break; - - /* A start or end tag whose tag name is one of: "event-source", - "section", "nav", "article", "aside", "header", "footer", - "datagrid", "command" */ - case 'event-source': case 'section': case 'nav': case 'article': - case 'aside': case 'header': case 'footer': case 'datagrid': - case 'command': - // Work in progress! - break; - - /* A start tag token not covered by the previous entries */ - default: - /* Reconstruct the active formatting elements, if any. */ - $this->reconstructActiveFormattingElements(); - - $this->insertElement($token, true, true); - break; - } - break; - - case HTML5::ENDTAG: - switch($token['name']) { - /* An end tag with the tag name "body" */ - case 'body': - /* If the second element in the stack of open elements is - not a body element, this is a parse error. Ignore the token. - (innerHTML case) */ - if(count($this->stack) < 2 || $this->stack[1]->nodeName !== 'body') { - // Ignore. - - /* If the current node is not the body element, then this - is a parse error. */ - } elseif(end($this->stack)->nodeName !== 'body') { - // Parse error. - } - - /* Change the insertion mode to "after body". */ - $this->mode = self::AFTER_BODY; - break; - - /* An end tag with the tag name "html" */ - case 'html': - /* Act as if an end tag with tag name "body" had been seen, - then, if that token wasn't ignored, reprocess the current - token. */ - $this->inBody(array( - 'name' => 'body', - 'type' => HTML5::ENDTAG - )); - - return $this->afterBody($token); - break; - - /* An end tag whose tag name is one of: "address", "blockquote", - "center", "dir", "div", "dl", "fieldset", "listing", "menu", - "ol", "pre", "ul" */ - case 'address': case 'blockquote': case 'center': case 'dir': - case 'div': case 'dl': case 'fieldset': case 'listing': - case 'menu': case 'ol': case 'pre': case 'ul': - /* If the stack of open elements has an element in scope - with the same tag name as that of the token, then generate - implied end tags. */ - if($this->elementInScope($token['name'])) { - $this->generateImpliedEndTags(); - - /* Now, if the current node is not an element with - the same tag name as that of the token, then this - is a parse error. */ - // w/e - - /* If the stack of open elements has an element in - scope with the same tag name as that of the token, - then pop elements from this stack until an element - with that tag name has been popped from the stack. */ - for($n = count($this->stack) - 1; $n >= 0; $n--) { - if($this->stack[$n]->nodeName === $token['name']) { - $n = -1; - } - - array_pop($this->stack); - } - } - break; - - /* An end tag whose tag name is "form" */ - case 'form': - /* If the stack of open elements has an element in scope - with the same tag name as that of the token, then generate - implied end tags. */ - if($this->elementInScope($token['name'])) { - $this->generateImpliedEndTags(); - - } - - if(end($this->stack)->nodeName !== $token['name']) { - /* Now, if the current node is not an element with the - same tag name as that of the token, then this is a parse - error. */ - // w/e - - } else { - /* Otherwise, if the current node is an element with - the same tag name as that of the token pop that element - from the stack. */ - array_pop($this->stack); - } - - /* In any case, set the form element pointer to null. */ - $this->form_pointer = null; - break; - - /* An end tag whose tag name is "p" */ - case 'p': - /* If the stack of open elements has a p element in scope, - then generate implied end tags, except for p elements. */ - if($this->elementInScope('p')) { - $this->generateImpliedEndTags(array('p')); - - /* If the current node is not a p element, then this is - a parse error. */ - // k - - /* If the stack of open elements has a p element in - scope, then pop elements from this stack until the stack - no longer has a p element in scope. */ - for($n = count($this->stack) - 1; $n >= 0; $n--) { - if($this->elementInScope('p')) { - array_pop($this->stack); - - } else { - break; - } - } - } - break; - - /* An end tag whose tag name is "dd", "dt", or "li" */ - case 'dd': case 'dt': case 'li': - /* If the stack of open elements has an element in scope - whose tag name matches the tag name of the token, then - generate implied end tags, except for elements with the - same tag name as the token. */ - if($this->elementInScope($token['name'])) { - $this->generateImpliedEndTags(array($token['name'])); - - /* If the current node is not an element with the same - tag name as the token, then this is a parse error. */ - // w/e - - /* If the stack of open elements has an element in scope - whose tag name matches the tag name of the token, then - pop elements from this stack until an element with that - tag name has been popped from the stack. */ - for($n = count($this->stack) - 1; $n >= 0; $n--) { - if($this->stack[$n]->nodeName === $token['name']) { - $n = -1; - } - - array_pop($this->stack); - } - } - break; - - /* An end tag whose tag name is one of: "h1", "h2", "h3", "h4", - "h5", "h6" */ - case 'h1': case 'h2': case 'h3': case 'h4': case 'h5': case 'h6': - $elements = array('h1', 'h2', 'h3', 'h4', 'h5', 'h6'); - - /* If the stack of open elements has in scope an element whose - tag name is one of "h1", "h2", "h3", "h4", "h5", or "h6", then - generate implied end tags. */ - if($this->elementInScope($elements)) { - $this->generateImpliedEndTags(); - - /* Now, if the current node is not an element with the same - tag name as that of the token, then this is a parse error. */ - // w/e - - /* If the stack of open elements has in scope an element - whose tag name is one of "h1", "h2", "h3", "h4", "h5", or - "h6", then pop elements from the stack until an element - with one of those tag names has been popped from the stack. */ - while($this->elementInScope($elements)) { - array_pop($this->stack); - } - } - break; - - /* An end tag whose tag name is one of: "a", "b", "big", "em", - "font", "i", "nobr", "s", "small", "strike", "strong", "tt", "u" */ - case 'a': case 'b': case 'big': case 'em': case 'font': - case 'i': case 'nobr': case 's': case 'small': case 'strike': - case 'strong': case 'tt': case 'u': - /* 1. Let the formatting element be the last element in - the list of active formatting elements that: - * is between the end of the list and the last scope - marker in the list, if any, or the start of the list - otherwise, and - * has the same tag name as the token. - */ - while(true) { - for($a = count($this->a_formatting) - 1; $a >= 0; $a--) { - if($this->a_formatting[$a] === self::MARKER) { - break; - - } elseif($this->a_formatting[$a]->tagName === $token['name']) { - $formatting_element = $this->a_formatting[$a]; - $in_stack = in_array($formatting_element, $this->stack, true); - $fe_af_pos = $a; - break; - } - } - - /* If there is no such node, or, if that node is - also in the stack of open elements but the element - is not in scope, then this is a parse error. Abort - these steps. The token is ignored. */ - if(!isset($formatting_element) || ($in_stack && - !$this->elementInScope($token['name']))) { - break; - - /* Otherwise, if there is such a node, but that node - is not in the stack of open elements, then this is a - parse error; remove the element from the list, and - abort these steps. */ - } elseif(isset($formatting_element) && !$in_stack) { - unset($this->a_formatting[$fe_af_pos]); - $this->a_formatting = array_merge($this->a_formatting); - break; - } - - /* 2. Let the furthest block be the topmost node in the - stack of open elements that is lower in the stack - than the formatting element, and is not an element in - the phrasing or formatting categories. There might - not be one. */ - $fe_s_pos = array_search($formatting_element, $this->stack, true); - $length = count($this->stack); - - for($s = $fe_s_pos + 1; $s < $length; $s++) { - $category = $this->getElementCategory($this->stack[$s]->nodeName); - - if($category !== self::PHRASING && $category !== self::FORMATTING) { - $furthest_block = $this->stack[$s]; - } - } - - /* 3. If there is no furthest block, then the UA must - skip the subsequent steps and instead just pop all - the nodes from the bottom of the stack of open - elements, from the current node up to the formatting - element, and remove the formatting element from the - list of active formatting elements. */ - if(!isset($furthest_block)) { - for($n = $length - 1; $n >= $fe_s_pos; $n--) { - array_pop($this->stack); - } - - unset($this->a_formatting[$fe_af_pos]); - $this->a_formatting = array_merge($this->a_formatting); - break; - } - - /* 4. Let the common ancestor be the element - immediately above the formatting element in the stack - of open elements. */ - $common_ancestor = $this->stack[$fe_s_pos - 1]; - - /* 5. If the furthest block has a parent node, then - remove the furthest block from its parent node. */ - if($furthest_block->parentNode !== null) { - $furthest_block->parentNode->removeChild($furthest_block); - } - - /* 6. Let a bookmark note the position of the - formatting element in the list of active formatting - elements relative to the elements on either side - of it in the list. */ - $bookmark = $fe_af_pos; - - /* 7. Let node and last node be the furthest block. - Follow these steps: */ - $node = $furthest_block; - $last_node = $furthest_block; - - while(true) { - for($n = array_search($node, $this->stack, true) - 1; $n >= 0; $n--) { - /* 7.1 Let node be the element immediately - prior to node in the stack of open elements. */ - $node = $this->stack[$n]; - - /* 7.2 If node is not in the list of active - formatting elements, then remove node from - the stack of open elements and then go back - to step 1. */ - if(!in_array($node, $this->a_formatting, true)) { - unset($this->stack[$n]); - $this->stack = array_merge($this->stack); - - } else { - break; - } - } - - /* 7.3 Otherwise, if node is the formatting - element, then go to the next step in the overall - algorithm. */ - if($node === $formatting_element) { - break; - - /* 7.4 Otherwise, if last node is the furthest - block, then move the aforementioned bookmark to - be immediately after the node in the list of - active formatting elements. */ - } elseif($last_node === $furthest_block) { - $bookmark = array_search($node, $this->a_formatting, true) + 1; - } - - /* 7.5 If node has any children, perform a - shallow clone of node, replace the entry for - node in the list of active formatting elements - with an entry for the clone, replace the entry - for node in the stack of open elements with an - entry for the clone, and let node be the clone. */ - if($node->hasChildNodes()) { - $clone = $node->cloneNode(); - $s_pos = array_search($node, $this->stack, true); - $a_pos = array_search($node, $this->a_formatting, true); - - $this->stack[$s_pos] = $clone; - $this->a_formatting[$a_pos] = $clone; - $node = $clone; - } - - /* 7.6 Insert last node into node, first removing - it from its previous parent node if any. */ - if($last_node->parentNode !== null) { - $last_node->parentNode->removeChild($last_node); - } - - $node->appendChild($last_node); - - /* 7.7 Let last node be node. */ - $last_node = $node; - } - - /* 8. Insert whatever last node ended up being in - the previous step into the common ancestor node, - first removing it from its previous parent node if - any. */ - if($last_node->parentNode !== null) { - $last_node->parentNode->removeChild($last_node); - } - - $common_ancestor->appendChild($last_node); - - /* 9. Perform a shallow clone of the formatting - element. */ - $clone = $formatting_element->cloneNode(); - - /* 10. Take all of the child nodes of the furthest - block and append them to the clone created in the - last step. */ - while($furthest_block->hasChildNodes()) { - $child = $furthest_block->firstChild; - $furthest_block->removeChild($child); - $clone->appendChild($child); - } - - /* 11. Append that clone to the furthest block. */ - $furthest_block->appendChild($clone); - - /* 12. Remove the formatting element from the list - of active formatting elements, and insert the clone - into the list of active formatting elements at the - position of the aforementioned bookmark. */ - $fe_af_pos = array_search($formatting_element, $this->a_formatting, true); - unset($this->a_formatting[$fe_af_pos]); - $this->a_formatting = array_merge($this->a_formatting); - - $af_part1 = array_slice($this->a_formatting, 0, $bookmark - 1); - $af_part2 = array_slice($this->a_formatting, $bookmark, count($this->a_formatting)); - $this->a_formatting = array_merge($af_part1, array($clone), $af_part2); - - /* 13. Remove the formatting element from the stack - of open elements, and insert the clone into the stack - of open elements immediately after (i.e. in a more - deeply nested position than) the position of the - furthest block in that stack. */ - $fe_s_pos = array_search($formatting_element, $this->stack, true); - $fb_s_pos = array_search($furthest_block, $this->stack, true); - unset($this->stack[$fe_s_pos]); - - $s_part1 = array_slice($this->stack, 0, $fb_s_pos); - $s_part2 = array_slice($this->stack, $fb_s_pos + 1, count($this->stack)); - $this->stack = array_merge($s_part1, array($clone), $s_part2); - - /* 14. Jump back to step 1 in this series of steps. */ - unset($formatting_element, $fe_af_pos, $fe_s_pos, $furthest_block); - } - break; - - /* An end tag token whose tag name is one of: "button", - "marquee", "object" */ - case 'button': case 'marquee': case 'object': - /* If the stack of open elements has an element in scope whose - tag name matches the tag name of the token, then generate implied - tags. */ - if($this->elementInScope($token['name'])) { - $this->generateImpliedEndTags(); - - /* Now, if the current node is not an element with the same - tag name as the token, then this is a parse error. */ - // k - - /* Now, if the stack of open elements has an element in scope - whose tag name matches the tag name of the token, then pop - elements from the stack until that element has been popped from - the stack, and clear the list of active formatting elements up - to the last marker. */ - for($n = count($this->stack) - 1; $n >= 0; $n--) { - if($this->stack[$n]->nodeName === $token['name']) { - $n = -1; - } - - array_pop($this->stack); - } - - $marker = end(array_keys($this->a_formatting, self::MARKER, true)); - - for($n = count($this->a_formatting) - 1; $n > $marker; $n--) { - array_pop($this->a_formatting); - } - } - break; - - /* Or an end tag whose tag name is one of: "area", "basefont", - "bgsound", "br", "embed", "hr", "iframe", "image", "img", - "input", "isindex", "noembed", "noframes", "param", "select", - "spacer", "table", "textarea", "wbr" */ - case 'area': case 'basefont': case 'bgsound': case 'br': - case 'embed': case 'hr': case 'iframe': case 'image': - case 'img': case 'input': case 'isindex': case 'noembed': - case 'noframes': case 'param': case 'select': case 'spacer': - case 'table': case 'textarea': case 'wbr': - // Parse error. Ignore the token. - break; - - /* An end tag token not covered by the previous entries */ - default: - for($n = count($this->stack) - 1; $n >= 0; $n--) { - /* Initialise node to be the current node (the bottommost - node of the stack). */ - $node = end($this->stack); - - /* If node has the same tag name as the end tag token, - then: */ - if($token['name'] === $node->nodeName) { - /* Generate implied end tags. */ - $this->generateImpliedEndTags(); - - /* If the tag name of the end tag token does not - match the tag name of the current node, this is a - parse error. */ - // k - - /* Pop all the nodes from the current node up to - node, including node, then stop this algorithm. */ - for($x = count($this->stack) - $n; $x >= $n; $x--) { - array_pop($this->stack); - } - - } else { - $category = $this->getElementCategory($node); - - if($category !== self::SPECIAL && $category !== self::SCOPING) { - /* Otherwise, if node is in neither the formatting - category nor the phrasing category, then this is a - parse error. Stop this algorithm. The end tag token - is ignored. */ - return false; - } - } - } - break; - } - break; - } - } - - private function inTable($token) { - $clear = array('html', 'table'); - - /* A character token that is one of one of U+0009 CHARACTER TABULATION, - U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED (FF), - or U+0020 SPACE */ - if($token['type'] === HTML5::CHARACTR && - preg_match('/^[\t\n\x0b\x0c ]+$/', $token['data'])) { - /* Append the character to the current node. */ - $text = $this->dom->createTextNode($token['data']); - end($this->stack)->appendChild($text); - - /* A comment token */ - } elseif($token['type'] === HTML5::COMMENT) { - /* Append a Comment node to the current node with the data - attribute set to the data given in the comment token. */ - $comment = $this->dom->createComment($token['data']); - end($this->stack)->appendChild($comment); - - /* A start tag whose tag name is "caption" */ - } elseif($token['type'] === HTML5::STARTTAG && - $token['name'] === 'caption') { - /* Clear the stack back to a table context. */ - $this->clearStackToTableContext($clear); - - /* Insert a marker at the end of the list of active - formatting elements. */ - $this->a_formatting[] = self::MARKER; - - /* Insert an HTML element for the token, then switch the - insertion mode to "in caption". */ - $this->insertElement($token); - $this->mode = self::IN_CAPTION; - - /* A start tag whose tag name is "colgroup" */ - } elseif($token['type'] === HTML5::STARTTAG && - $token['name'] === 'colgroup') { - /* Clear the stack back to a table context. */ - $this->clearStackToTableContext($clear); - - /* Insert an HTML element for the token, then switch the - insertion mode to "in column group". */ - $this->insertElement($token); - $this->mode = self::IN_CGROUP; - - /* A start tag whose tag name is "col" */ - } elseif($token['type'] === HTML5::STARTTAG && - $token['name'] === 'col') { - $this->inTable(array( - 'name' => 'colgroup', - 'type' => HTML5::STARTTAG, - 'attr' => array() - )); - - $this->inColumnGroup($token); - - /* A start tag whose tag name is one of: "tbody", "tfoot", "thead" */ - } elseif($token['type'] === HTML5::STARTTAG && in_array($token['name'], - array('tbody', 'tfoot', 'thead'))) { - /* Clear the stack back to a table context. */ - $this->clearStackToTableContext($clear); - - /* Insert an HTML element for the token, then switch the insertion - mode to "in table body". */ - $this->insertElement($token); - $this->mode = self::IN_TBODY; - - /* A start tag whose tag name is one of: "td", "th", "tr" */ - } elseif($token['type'] === HTML5::STARTTAG && - in_array($token['name'], array('td', 'th', 'tr'))) { - /* Act as if a start tag token with the tag name "tbody" had been - seen, then reprocess the current token. */ - $this->inTable(array( - 'name' => 'tbody', - 'type' => HTML5::STARTTAG, - 'attr' => array() - )); - - return $this->inTableBody($token); - - /* A start tag whose tag name is "table" */ - } elseif($token['type'] === HTML5::STARTTAG && - $token['name'] === 'table') { - /* Parse error. Act as if an end tag token with the tag name "table" - had been seen, then, if that token wasn't ignored, reprocess the - current token. */ - $this->inTable(array( - 'name' => 'table', - 'type' => HTML5::ENDTAG - )); - - return $this->mainPhase($token); - - /* An end tag whose tag name is "table" */ - } elseif($token['type'] === HTML5::ENDTAG && - $token['name'] === 'table') { - /* If the stack of open elements does not have an element in table - scope with the same tag name as the token, this is a parse error. - Ignore the token. (innerHTML case) */ - if(!$this->elementInScope($token['name'], true)) { - return false; - - /* Otherwise: */ - } else { - /* Generate implied end tags. */ - $this->generateImpliedEndTags(); - - /* Now, if the current node is not a table element, then this - is a parse error. */ - // w/e - - /* Pop elements from this stack until a table element has been - popped from the stack. */ - while(true) { - $current = end($this->stack)->nodeName; - array_pop($this->stack); - - if($current === 'table') { - break; - } - } - - /* Reset the insertion mode appropriately. */ - $this->resetInsertionMode(); - } - - /* An end tag whose tag name is one of: "body", "caption", "col", - "colgroup", "html", "tbody", "td", "tfoot", "th", "thead", "tr" */ - } elseif($token['type'] === HTML5::ENDTAG && in_array($token['name'], - array('body', 'caption', 'col', 'colgroup', 'html', 'tbody', 'td', - 'tfoot', 'th', 'thead', 'tr'))) { - // Parse error. Ignore the token. - - /* Anything else */ - } else { - /* Parse error. Process the token as if the insertion mode was "in - body", with the following exception: */ - - /* If the current node is a table, tbody, tfoot, thead, or tr - element, then, whenever a node would be inserted into the current - node, it must instead be inserted into the foster parent element. */ - if(in_array(end($this->stack)->nodeName, - array('table', 'tbody', 'tfoot', 'thead', 'tr'))) { - /* The foster parent element is the parent element of the last - table element in the stack of open elements, if there is a - table element and it has such a parent element. If there is no - table element in the stack of open elements (innerHTML case), - then the foster parent element is the first element in the - stack of open elements (the html element). Otherwise, if there - is a table element in the stack of open elements, but the last - table element in the stack of open elements has no parent, or - its parent node is not an element, then the foster parent - element is the element before the last table element in the - stack of open elements. */ - for($n = count($this->stack) - 1; $n >= 0; $n--) { - if($this->stack[$n]->nodeName === 'table') { - $table = $this->stack[$n]; - break; - } - } - - if(isset($table) && $table->parentNode !== null) { - $this->foster_parent = $table->parentNode; - - } elseif(!isset($table)) { - $this->foster_parent = $this->stack[0]; - - } elseif(isset($table) && ($table->parentNode === null || - $table->parentNode->nodeType !== XML_ELEMENT_NODE)) { - $this->foster_parent = $this->stack[$n - 1]; - } - } - - $this->inBody($token); - } - } - - private function inCaption($token) { - /* An end tag whose tag name is "caption" */ - if($token['type'] === HTML5::ENDTAG && $token['name'] === 'caption') { - /* If the stack of open elements does not have an element in table - scope with the same tag name as the token, this is a parse error. - Ignore the token. (innerHTML case) */ - if(!$this->elementInScope($token['name'], true)) { - // Ignore - - /* Otherwise: */ - } else { - /* Generate implied end tags. */ - $this->generateImpliedEndTags(); - - /* Now, if the current node is not a caption element, then this - is a parse error. */ - // w/e - - /* Pop elements from this stack until a caption element has - been popped from the stack. */ - while(true) { - $node = end($this->stack)->nodeName; - array_pop($this->stack); - - if($node === 'caption') { - break; - } - } - - /* Clear the list of active formatting elements up to the last - marker. */ - $this->clearTheActiveFormattingElementsUpToTheLastMarker(); - - /* Switch the insertion mode to "in table". */ - $this->mode = self::IN_TABLE; - } - - /* A start tag whose tag name is one of: "caption", "col", "colgroup", - "tbody", "td", "tfoot", "th", "thead", "tr", or an end tag whose tag - name is "table" */ - } elseif(($token['type'] === HTML5::STARTTAG && in_array($token['name'], - array('caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th', - 'thead', 'tr'))) || ($token['type'] === HTML5::ENDTAG && - $token['name'] === 'table')) { - /* Parse error. Act as if an end tag with the tag name "caption" - had been seen, then, if that token wasn't ignored, reprocess the - current token. */ - $this->inCaption(array( - 'name' => 'caption', - 'type' => HTML5::ENDTAG - )); - - return $this->inTable($token); - - /* An end tag whose tag name is one of: "body", "col", "colgroup", - "html", "tbody", "td", "tfoot", "th", "thead", "tr" */ - } elseif($token['type'] === HTML5::ENDTAG && in_array($token['name'], - array('body', 'col', 'colgroup', 'html', 'tbody', 'tfoot', 'th', - 'thead', 'tr'))) { - // Parse error. Ignore the token. - - /* Anything else */ - } else { - /* Process the token as if the insertion mode was "in body". */ - $this->inBody($token); - } - } - - private function inColumnGroup($token) { - /* A character token that is one of one of U+0009 CHARACTER TABULATION, - U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED (FF), - or U+0020 SPACE */ - if($token['type'] === HTML5::CHARACTR && - preg_match('/^[\t\n\x0b\x0c ]+$/', $token['data'])) { - /* Append the character to the current node. */ - $text = $this->dom->createTextNode($token['data']); - end($this->stack)->appendChild($text); - - /* A comment token */ - } elseif($token['type'] === HTML5::COMMENT) { - /* Append a Comment node to the current node with the data - attribute set to the data given in the comment token. */ - $comment = $this->dom->createComment($token['data']); - end($this->stack)->appendChild($comment); - - /* A start tag whose tag name is "col" */ - } elseif($token['type'] === HTML5::STARTTAG && $token['name'] === 'col') { - /* Insert a col element for the token. Immediately pop the current - node off the stack of open elements. */ - $this->insertElement($token); - array_pop($this->stack); - - /* An end tag whose tag name is "colgroup" */ - } elseif($token['type'] === HTML5::ENDTAG && - $token['name'] === 'colgroup') { - /* If the current node is the root html element, then this is a - parse error, ignore the token. (innerHTML case) */ - if(end($this->stack)->nodeName === 'html') { - // Ignore - - /* Otherwise, pop the current node (which will be a colgroup - element) from the stack of open elements. Switch the insertion - mode to "in table". */ - } else { - array_pop($this->stack); - $this->mode = self::IN_TABLE; - } - - /* An end tag whose tag name is "col" */ - } elseif($token['type'] === HTML5::ENDTAG && $token['name'] === 'col') { - /* Parse error. Ignore the token. */ - - /* Anything else */ - } else { - /* Act as if an end tag with the tag name "colgroup" had been seen, - and then, if that token wasn't ignored, reprocess the current token. */ - $this->inColumnGroup(array( - 'name' => 'colgroup', - 'type' => HTML5::ENDTAG - )); - - return $this->inTable($token); - } - } - - private function inTableBody($token) { - $clear = array('tbody', 'tfoot', 'thead', 'html'); - - /* A start tag whose tag name is "tr" */ - if($token['type'] === HTML5::STARTTAG && $token['name'] === 'tr') { - /* Clear the stack back to a table body context. */ - $this->clearStackToTableContext($clear); - - /* Insert a tr element for the token, then switch the insertion - mode to "in row". */ - $this->insertElement($token); - $this->mode = self::IN_ROW; - - /* A start tag whose tag name is one of: "th", "td" */ - } elseif($token['type'] === HTML5::STARTTAG && - ($token['name'] === 'th' || $token['name'] === 'td')) { - /* Parse error. Act as if a start tag with the tag name "tr" had - been seen, then reprocess the current token. */ - $this->inTableBody(array( - 'name' => 'tr', - 'type' => HTML5::STARTTAG, - 'attr' => array() - )); - - return $this->inRow($token); - - /* An end tag whose tag name is one of: "tbody", "tfoot", "thead" */ - } elseif($token['type'] === HTML5::ENDTAG && - in_array($token['name'], array('tbody', 'tfoot', 'thead'))) { - /* If the stack of open elements does not have an element in table - scope with the same tag name as the token, this is a parse error. - Ignore the token. */ - if(!$this->elementInScope($token['name'], true)) { - // Ignore - - /* Otherwise: */ - } else { - /* Clear the stack back to a table body context. */ - $this->clearStackToTableContext($clear); - - /* Pop the current node from the stack of open elements. Switch - the insertion mode to "in table". */ - array_pop($this->stack); - $this->mode = self::IN_TABLE; - } - - /* A start tag whose tag name is one of: "caption", "col", "colgroup", - "tbody", "tfoot", "thead", or an end tag whose tag name is "table" */ - } elseif(($token['type'] === HTML5::STARTTAG && in_array($token['name'], - array('caption', 'col', 'colgroup', 'tbody', 'tfoor', 'thead'))) || - ($token['type'] === HTML5::STARTTAG && $token['name'] === 'table')) { - /* If the stack of open elements does not have a tbody, thead, or - tfoot element in table scope, this is a parse error. Ignore the - token. (innerHTML case) */ - if(!$this->elementInScope(array('tbody', 'thead', 'tfoot'), true)) { - // Ignore. - - /* Otherwise: */ - } else { - /* Clear the stack back to a table body context. */ - $this->clearStackToTableContext($clear); - - /* Act as if an end tag with the same tag name as the current - node ("tbody", "tfoot", or "thead") had been seen, then - reprocess the current token. */ - $this->inTableBody(array( - 'name' => end($this->stack)->nodeName, - 'type' => HTML5::ENDTAG - )); - - return $this->mainPhase($token); - } - - /* An end tag whose tag name is one of: "body", "caption", "col", - "colgroup", "html", "td", "th", "tr" */ - } elseif($token['type'] === HTML5::ENDTAG && in_array($token['name'], - array('body', 'caption', 'col', 'colgroup', 'html', 'td', 'th', 'tr'))) { - /* Parse error. Ignore the token. */ - - /* Anything else */ - } else { - /* Process the token as if the insertion mode was "in table". */ - $this->inTable($token); - } - } - - private function inRow($token) { - $clear = array('tr', 'html'); - - /* A start tag whose tag name is one of: "th", "td" */ - if($token['type'] === HTML5::STARTTAG && - ($token['name'] === 'th' || $token['name'] === 'td')) { - /* Clear the stack back to a table row context. */ - $this->clearStackToTableContext($clear); - - /* Insert an HTML element for the token, then switch the insertion - mode to "in cell". */ - $this->insertElement($token); - $this->mode = self::IN_CELL; - - /* Insert a marker at the end of the list of active formatting - elements. */ - $this->a_formatting[] = self::MARKER; - - /* An end tag whose tag name is "tr" */ - } elseif($token['type'] === HTML5::ENDTAG && $token['name'] === 'tr') { - /* If the stack of open elements does not have an element in table - scope with the same tag name as the token, this is a parse error. - Ignore the token. (innerHTML case) */ - if(!$this->elementInScope($token['name'], true)) { - // Ignore. - - /* Otherwise: */ - } else { - /* Clear the stack back to a table row context. */ - $this->clearStackToTableContext($clear); - - /* Pop the current node (which will be a tr element) from the - stack of open elements. Switch the insertion mode to "in table - body". */ - array_pop($this->stack); - $this->mode = self::IN_TBODY; - } - - /* A start tag whose tag name is one of: "caption", "col", "colgroup", - "tbody", "tfoot", "thead", "tr" or an end tag whose tag name is "table" */ - } elseif($token['type'] === HTML5::STARTTAG && in_array($token['name'], - array('caption', 'col', 'colgroup', 'tbody', 'tfoot', 'thead', 'tr'))) { - /* Act as if an end tag with the tag name "tr" had been seen, then, - if that token wasn't ignored, reprocess the current token. */ - $this->inRow(array( - 'name' => 'tr', - 'type' => HTML5::ENDTAG - )); - - return $this->inCell($token); - - /* An end tag whose tag name is one of: "tbody", "tfoot", "thead" */ - } elseif($token['type'] === HTML5::ENDTAG && - in_array($token['name'], array('tbody', 'tfoot', 'thead'))) { - /* If the stack of open elements does not have an element in table - scope with the same tag name as the token, this is a parse error. - Ignore the token. */ - if(!$this->elementInScope($token['name'], true)) { - // Ignore. - - /* Otherwise: */ - } else { - /* Otherwise, act as if an end tag with the tag name "tr" had - been seen, then reprocess the current token. */ - $this->inRow(array( - 'name' => 'tr', - 'type' => HTML5::ENDTAG - )); - - return $this->inCell($token); - } - - /* An end tag whose tag name is one of: "body", "caption", "col", - "colgroup", "html", "td", "th" */ - } elseif($token['type'] === HTML5::ENDTAG && in_array($token['name'], - array('body', 'caption', 'col', 'colgroup', 'html', 'td', 'th', 'tr'))) { - /* Parse error. Ignore the token. */ - - /* Anything else */ - } else { - /* Process the token as if the insertion mode was "in table". */ - $this->inTable($token); - } - } - - private function inCell($token) { - /* An end tag whose tag name is one of: "td", "th" */ - if($token['type'] === HTML5::ENDTAG && - ($token['name'] === 'td' || $token['name'] === 'th')) { - /* If the stack of open elements does not have an element in table - scope with the same tag name as that of the token, then this is a - parse error and the token must be ignored. */ - if(!$this->elementInScope($token['name'], true)) { - // Ignore. - - /* Otherwise: */ - } else { - /* Generate implied end tags, except for elements with the same - tag name as the token. */ - $this->generateImpliedEndTags(array($token['name'])); - - /* Now, if the current node is not an element with the same tag - name as the token, then this is a parse error. */ - // k - - /* Pop elements from this stack until an element with the same - tag name as the token has been popped from the stack. */ - while(true) { - $node = end($this->stack)->nodeName; - array_pop($this->stack); - - if($node === $token['name']) { - break; - } - } - - /* Clear the list of active formatting elements up to the last - marker. */ - $this->clearTheActiveFormattingElementsUpToTheLastMarker(); - - /* Switch the insertion mode to "in row". (The current node - will be a tr element at this point.) */ - $this->mode = self::IN_ROW; - } - - /* A start tag whose tag name is one of: "caption", "col", "colgroup", - "tbody", "td", "tfoot", "th", "thead", "tr" */ - } elseif($token['type'] === HTML5::STARTTAG && in_array($token['name'], - array('caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th', - 'thead', 'tr'))) { - /* If the stack of open elements does not have a td or th element - in table scope, then this is a parse error; ignore the token. - (innerHTML case) */ - if(!$this->elementInScope(array('td', 'th'), true)) { - // Ignore. - - /* Otherwise, close the cell (see below) and reprocess the current - token. */ - } else { - $this->closeCell(); - return $this->inRow($token); - } - - /* A start tag whose tag name is one of: "caption", "col", "colgroup", - "tbody", "td", "tfoot", "th", "thead", "tr" */ - } elseif($token['type'] === HTML5::STARTTAG && in_array($token['name'], - array('caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th', - 'thead', 'tr'))) { - /* If the stack of open elements does not have a td or th element - in table scope, then this is a parse error; ignore the token. - (innerHTML case) */ - if(!$this->elementInScope(array('td', 'th'), true)) { - // Ignore. - - /* Otherwise, close the cell (see below) and reprocess the current - token. */ - } else { - $this->closeCell(); - return $this->inRow($token); - } - - /* An end tag whose tag name is one of: "body", "caption", "col", - "colgroup", "html" */ - } elseif($token['type'] === HTML5::ENDTAG && in_array($token['name'], - array('body', 'caption', 'col', 'colgroup', 'html'))) { - /* Parse error. Ignore the token. */ - - /* An end tag whose tag name is one of: "table", "tbody", "tfoot", - "thead", "tr" */ - } elseif($token['type'] === HTML5::ENDTAG && in_array($token['name'], - array('table', 'tbody', 'tfoot', 'thead', 'tr'))) { - /* If the stack of open elements does not have an element in table - scope with the same tag name as that of the token (which can only - happen for "tbody", "tfoot" and "thead", or, in the innerHTML case), - then this is a parse error and the token must be ignored. */ - if(!$this->elementInScope($token['name'], true)) { - // Ignore. - - /* Otherwise, close the cell (see below) and reprocess the current - token. */ - } else { - $this->closeCell(); - return $this->inRow($token); - } - - /* Anything else */ - } else { - /* Process the token as if the insertion mode was "in body". */ - $this->inBody($token); - } - } - - private function inSelect($token) { - /* Handle the token as follows: */ - - /* A character token */ - if($token['type'] === HTML5::CHARACTR) { - /* Append the token's character to the current node. */ - $this->insertText($token['data']); - - /* A comment token */ - } elseif($token['type'] === HTML5::COMMENT) { - /* Append a Comment node to the current node with the data - attribute set to the data given in the comment token. */ - $this->insertComment($token['data']); - - /* A start tag token whose tag name is "option" */ - } elseif($token['type'] === HTML5::STARTTAG && - $token['name'] === 'option') { - /* If the current node is an option element, act as if an end tag - with the tag name "option" had been seen. */ - if(end($this->stack)->nodeName === 'option') { - $this->inSelect(array( - 'name' => 'option', - 'type' => HTML5::ENDTAG - )); - } - - /* Insert an HTML element for the token. */ - $this->insertElement($token); - - /* A start tag token whose tag name is "optgroup" */ - } elseif($token['type'] === HTML5::STARTTAG && - $token['name'] === 'optgroup') { - /* If the current node is an option element, act as if an end tag - with the tag name "option" had been seen. */ - if(end($this->stack)->nodeName === 'option') { - $this->inSelect(array( - 'name' => 'option', - 'type' => HTML5::ENDTAG - )); - } - - /* If the current node is an optgroup element, act as if an end tag - with the tag name "optgroup" had been seen. */ - if(end($this->stack)->nodeName === 'optgroup') { - $this->inSelect(array( - 'name' => 'optgroup', - 'type' => HTML5::ENDTAG - )); - } - - /* Insert an HTML element for the token. */ - $this->insertElement($token); - - /* An end tag token whose tag name is "optgroup" */ - } elseif($token['type'] === HTML5::ENDTAG && - $token['name'] === 'optgroup') { - /* First, if the current node is an option element, and the node - immediately before it in the stack of open elements is an optgroup - element, then act as if an end tag with the tag name "option" had - been seen. */ - $elements_in_stack = count($this->stack); - - if($this->stack[$elements_in_stack - 1]->nodeName === 'option' && - $this->stack[$elements_in_stack - 2]->nodeName === 'optgroup') { - $this->inSelect(array( - 'name' => 'option', - 'type' => HTML5::ENDTAG - )); - } - - /* If the current node is an optgroup element, then pop that node - from the stack of open elements. Otherwise, this is a parse error, - ignore the token. */ - if($this->stack[$elements_in_stack - 1] === 'optgroup') { - array_pop($this->stack); - } - - /* An end tag token whose tag name is "option" */ - } elseif($token['type'] === HTML5::ENDTAG && - $token['name'] === 'option') { - /* If the current node is an option element, then pop that node - from the stack of open elements. Otherwise, this is a parse error, - ignore the token. */ - if(end($this->stack)->nodeName === 'option') { - array_pop($this->stack); - } - - /* An end tag whose tag name is "select" */ - } elseif($token['type'] === HTML5::ENDTAG && - $token['name'] === 'select') { - /* If the stack of open elements does not have an element in table - scope with the same tag name as the token, this is a parse error. - Ignore the token. (innerHTML case) */ - if(!$this->elementInScope($token['name'], true)) { - // w/e - - /* Otherwise: */ - } else { - /* Pop elements from the stack of open elements until a select - element has been popped from the stack. */ - while(true) { - $current = end($this->stack)->nodeName; - array_pop($this->stack); - - if($current === 'select') { - break; - } - } - - /* Reset the insertion mode appropriately. */ - $this->resetInsertionMode(); - } - - /* A start tag whose tag name is "select" */ - } elseif($token['name'] === 'select' && - $token['type'] === HTML5::STARTTAG) { - /* Parse error. Act as if the token had been an end tag with the - tag name "select" instead. */ - $this->inSelect(array( - 'name' => 'select', - 'type' => HTML5::ENDTAG - )); - - /* An end tag whose tag name is one of: "caption", "table", "tbody", - "tfoot", "thead", "tr", "td", "th" */ - } elseif(in_array($token['name'], array('caption', 'table', 'tbody', - 'tfoot', 'thead', 'tr', 'td', 'th')) && $token['type'] === HTML5::ENDTAG) { - /* Parse error. */ - // w/e - - /* If the stack of open elements has an element in table scope with - the same tag name as that of the token, then act as if an end tag - with the tag name "select" had been seen, and reprocess the token. - Otherwise, ignore the token. */ - if($this->elementInScope($token['name'], true)) { - $this->inSelect(array( - 'name' => 'select', - 'type' => HTML5::ENDTAG - )); - - $this->mainPhase($token); - } - - /* Anything else */ - } else { - /* Parse error. Ignore the token. */ - } - } - - private function afterBody($token) { - /* Handle the token as follows: */ - - /* A character token that is one of one of U+0009 CHARACTER TABULATION, - U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED (FF), - or U+0020 SPACE */ - if($token['type'] === HTML5::CHARACTR && - preg_match('/^[\t\n\x0b\x0c ]+$/', $token['data'])) { - /* Process the token as it would be processed if the insertion mode - was "in body". */ - $this->inBody($token); - - /* A comment token */ - } elseif($token['type'] === HTML5::COMMENT) { - /* Append a Comment node to the first element in the stack of open - elements (the html element), with the data attribute set to the - data given in the comment token. */ - $comment = $this->dom->createComment($token['data']); - $this->stack[0]->appendChild($comment); - - /* An end tag with the tag name "html" */ - } elseif($token['type'] === HTML5::ENDTAG && $token['name'] === 'html') { - /* If the parser was originally created in order to handle the - setting of an element's innerHTML attribute, this is a parse error; - ignore the token. (The element will be an html element in this - case.) (innerHTML case) */ - - /* Otherwise, switch to the trailing end phase. */ - $this->phase = self::END_PHASE; - - /* Anything else */ - } else { - /* Parse error. Set the insertion mode to "in body" and reprocess - the token. */ - $this->mode = self::IN_BODY; - return $this->inBody($token); - } - } - - private function inFrameset($token) { - /* Handle the token as follows: */ - - /* A character token that is one of one of U+0009 CHARACTER TABULATION, - U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED (FF), - U+000D CARRIAGE RETURN (CR), or U+0020 SPACE */ - if($token['type'] === HTML5::CHARACTR && - preg_match('/^[\t\n\x0b\x0c ]+$/', $token['data'])) { - /* Append the character to the current node. */ - $this->insertText($token['data']); - - /* A comment token */ - } elseif($token['type'] === HTML5::COMMENT) { - /* Append a Comment node to the current node with the data - attribute set to the data given in the comment token. */ - $this->insertComment($token['data']); - - /* A start tag with the tag name "frameset" */ - } elseif($token['name'] === 'frameset' && - $token['type'] === HTML5::STARTTAG) { - $this->insertElement($token); - - /* An end tag with the tag name "frameset" */ - } elseif($token['name'] === 'frameset' && - $token['type'] === HTML5::ENDTAG) { - /* If the current node is the root html element, then this is a - parse error; ignore the token. (innerHTML case) */ - if(end($this->stack)->nodeName === 'html') { - // Ignore - - } else { - /* Otherwise, pop the current node from the stack of open - elements. */ - array_pop($this->stack); - - /* If the parser was not originally created in order to handle - the setting of an element's innerHTML attribute (innerHTML case), - and the current node is no longer a frameset element, then change - the insertion mode to "after frameset". */ - $this->mode = self::AFTR_FRAME; - } - - /* A start tag with the tag name "frame" */ - } elseif($token['name'] === 'frame' && - $token['type'] === HTML5::STARTTAG) { - /* Insert an HTML element for the token. */ - $this->insertElement($token); - - /* Immediately pop the current node off the stack of open elements. */ - array_pop($this->stack); - - /* A start tag with the tag name "noframes" */ - } elseif($token['name'] === 'noframes' && - $token['type'] === HTML5::STARTTAG) { - /* Process the token as if the insertion mode had been "in body". */ - $this->inBody($token); - - /* Anything else */ - } else { - /* Parse error. Ignore the token. */ - } - } - - private function afterFrameset($token) { - /* Handle the token as follows: */ - - /* A character token that is one of one of U+0009 CHARACTER TABULATION, - U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED (FF), - U+000D CARRIAGE RETURN (CR), or U+0020 SPACE */ - if($token['type'] === HTML5::CHARACTR && - preg_match('/^[\t\n\x0b\x0c ]+$/', $token['data'])) { - /* Append the character to the current node. */ - $this->insertText($token['data']); - - /* A comment token */ - } elseif($token['type'] === HTML5::COMMENT) { - /* Append a Comment node to the current node with the data - attribute set to the data given in the comment token. */ - $this->insertComment($token['data']); - - /* An end tag with the tag name "html" */ - } elseif($token['name'] === 'html' && - $token['type'] === HTML5::ENDTAG) { - /* Switch to the trailing end phase. */ - $this->phase = self::END_PHASE; - - /* A start tag with the tag name "noframes" */ - } elseif($token['name'] === 'noframes' && - $token['type'] === HTML5::STARTTAG) { - /* Process the token as if the insertion mode had been "in body". */ - $this->inBody($token); - - /* Anything else */ - } else { - /* Parse error. Ignore the token. */ - } - } - - private function trailingEndPhase($token) { - /* After the main phase, as each token is emitted from the tokenisation - stage, it must be processed as described in this section. */ - - /* A DOCTYPE token */ - if($token['type'] === HTML5::DOCTYPE) { - // Parse error. Ignore the token. - - /* A comment token */ - } elseif($token['type'] === HTML5::COMMENT) { - /* Append a Comment node to the Document object with the data - attribute set to the data given in the comment token. */ - $comment = $this->dom->createComment($token['data']); - $this->dom->appendChild($comment); - - /* A character token that is one of one of U+0009 CHARACTER TABULATION, - U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED (FF), - or U+0020 SPACE */ - } elseif($token['type'] === HTML5::CHARACTR && - preg_match('/^[\t\n\x0b\x0c ]+$/', $token['data'])) { - /* Process the token as it would be processed in the main phase. */ - $this->mainPhase($token); - - /* A character token that is not one of U+0009 CHARACTER TABULATION, - U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED (FF), - or U+0020 SPACE. Or a start tag token. Or an end tag token. */ - } elseif(($token['type'] === HTML5::CHARACTR && - preg_match('/^[\t\n\x0b\x0c ]+$/', $token['data'])) || - $token['type'] === HTML5::STARTTAG || $token['type'] === HTML5::ENDTAG) { - /* Parse error. Switch back to the main phase and reprocess the - token. */ - $this->phase = self::MAIN_PHASE; - return $this->mainPhase($token); - - /* An end-of-file token */ - } elseif($token['type'] === HTML5::EOF) { - /* OMG DONE!! */ - } - } - - private function insertElement($token, $append = true, $check = false) { - // Proprietary workaround for libxml2's limitations with tag names - if ($check) { - // Slightly modified HTML5 tag-name modification, - // removing anything that's not an ASCII letter, digit, or hyphen - $token['name'] = preg_replace('/[^a-z0-9-]/i', '', $token['name']); - // Remove leading hyphens and numbers - $token['name'] = ltrim($token['name'], '-0..9'); - // In theory, this should ever be needed, but just in case - if ($token['name'] === '') $token['name'] = 'span'; // arbitrary generic choice - } - - $el = $this->dom->createElement($token['name']); - - foreach($token['attr'] as $attr) { - if(!$el->hasAttribute($attr['name'])) { - $el->setAttribute($attr['name'], $attr['value']); - } - } - - $this->appendToRealParent($el); - $this->stack[] = $el; - - return $el; - } - - private function insertText($data) { - $text = $this->dom->createTextNode($data); - $this->appendToRealParent($text); - } - - private function insertComment($data) { - $comment = $this->dom->createComment($data); - $this->appendToRealParent($comment); - } - - private function appendToRealParent($node) { - if($this->foster_parent === null) { - end($this->stack)->appendChild($node); - - } elseif($this->foster_parent !== null) { - /* If the foster parent element is the parent element of the - last table element in the stack of open elements, then the new - node must be inserted immediately before the last table element - in the stack of open elements in the foster parent element; - otherwise, the new node must be appended to the foster parent - element. */ - for($n = count($this->stack) - 1; $n >= 0; $n--) { - if($this->stack[$n]->nodeName === 'table' && - $this->stack[$n]->parentNode !== null) { - $table = $this->stack[$n]; - break; - } - } - - if(isset($table) && $this->foster_parent->isSameNode($table->parentNode)) - $this->foster_parent->insertBefore($node, $table); - else - $this->foster_parent->appendChild($node); - - $this->foster_parent = null; - } - } - - private function elementInScope($el, $table = false) { - if(is_array($el)) { - foreach($el as $element) { - if($this->elementInScope($element, $table)) { - return true; - } - } - - return false; - } - - $leng = count($this->stack); - - for($n = 0; $n < $leng; $n++) { - /* 1. Initialise node to be the current node (the bottommost node of - the stack). */ - $node = $this->stack[$leng - 1 - $n]; - - if($node->tagName === $el) { - /* 2. If node is the target node, terminate in a match state. */ - return true; - - } elseif($node->tagName === 'table') { - /* 3. Otherwise, if node is a table element, terminate in a failure - state. */ - return false; - - } elseif($table === true && in_array($node->tagName, array('caption', 'td', - 'th', 'button', 'marquee', 'object'))) { - /* 4. Otherwise, if the algorithm is the "has an element in scope" - variant (rather than the "has an element in table scope" variant), - and node is one of the following, terminate in a failure state. */ - return false; - - } elseif($node === $node->ownerDocument->documentElement) { - /* 5. Otherwise, if node is an html element (root element), terminate - in a failure state. (This can only happen if the node is the topmost - node of the stack of open elements, and prevents the next step from - being invoked if there are no more elements in the stack.) */ - return false; - } - - /* Otherwise, set node to the previous entry in the stack of open - elements and return to step 2. (This will never fail, since the loop - will always terminate in the previous step if the top of the stack - is reached.) */ - } - } - - private function reconstructActiveFormattingElements() { - /* 1. If there are no entries in the list of active formatting elements, - then there is nothing to reconstruct; stop this algorithm. */ - $formatting_elements = count($this->a_formatting); - - if($formatting_elements === 0) { - return false; - } - - /* 3. Let entry be the last (most recently added) element in the list - of active formatting elements. */ - $entry = end($this->a_formatting); - - /* 2. If the last (most recently added) entry in the list of active - formatting elements is a marker, or if it is an element that is in the - stack of open elements, then there is nothing to reconstruct; stop this - algorithm. */ - if($entry === self::MARKER || in_array($entry, $this->stack, true)) { - return false; - } - - for($a = $formatting_elements - 1; $a >= 0; true) { - /* 4. If there are no entries before entry in the list of active - formatting elements, then jump to step 8. */ - if($a === 0) { - $step_seven = false; - break; - } - - /* 5. Let entry be the entry one earlier than entry in the list of - active formatting elements. */ - $a--; - $entry = $this->a_formatting[$a]; - - /* 6. If entry is neither a marker nor an element that is also in - thetack of open elements, go to step 4. */ - if($entry === self::MARKER || in_array($entry, $this->stack, true)) { - break; - } - } - - while(true) { - /* 7. Let entry be the element one later than entry in the list of - active formatting elements. */ - if(isset($step_seven) && $step_seven === true) { - $a++; - $entry = $this->a_formatting[$a]; - } - - /* 8. Perform a shallow clone of the element entry to obtain clone. */ - $clone = $entry->cloneNode(); - - /* 9. Append clone to the current node and push it onto the stack - of open elements so that it is the new current node. */ - end($this->stack)->appendChild($clone); - $this->stack[] = $clone; - - /* 10. Replace the entry for entry in the list with an entry for - clone. */ - $this->a_formatting[$a] = $clone; - - /* 11. If the entry for clone in the list of active formatting - elements is not the last entry in the list, return to step 7. */ - if(end($this->a_formatting) !== $clone) { - $step_seven = true; - } else { - break; - } - } - } - - private function clearTheActiveFormattingElementsUpToTheLastMarker() { - /* When the steps below require the UA to clear the list of active - formatting elements up to the last marker, the UA must perform the - following steps: */ - - while(true) { - /* 1. Let entry be the last (most recently added) entry in the list - of active formatting elements. */ - $entry = end($this->a_formatting); - - /* 2. Remove entry from the list of active formatting elements. */ - array_pop($this->a_formatting); - - /* 3. If entry was a marker, then stop the algorithm at this point. - The list has been cleared up to the last marker. */ - if($entry === self::MARKER) { - break; - } - } - } - - private function generateImpliedEndTags($exclude = array()) { - /* When the steps below require the UA to generate implied end tags, - then, if the current node is a dd element, a dt element, an li element, - a p element, a td element, a th element, or a tr element, the UA must - act as if an end tag with the respective tag name had been seen and - then generate implied end tags again. */ - $node = end($this->stack); - $elements = array_diff(array('dd', 'dt', 'li', 'p', 'td', 'th', 'tr'), $exclude); - - while(in_array(end($this->stack)->nodeName, $elements)) { - array_pop($this->stack); - } - } - - private function getElementCategory($node) { - $name = $node->tagName; - if(in_array($name, $this->special)) - return self::SPECIAL; - - elseif(in_array($name, $this->scoping)) - return self::SCOPING; - - elseif(in_array($name, $this->formatting)) - return self::FORMATTING; - - else - return self::PHRASING; - } - - private function clearStackToTableContext($elements) { - /* When the steps above require the UA to clear the stack back to a - table context, it means that the UA must, while the current node is not - a table element or an html element, pop elements from the stack of open - elements. If this causes any elements to be popped from the stack, then - this is a parse error. */ - while(true) { - $node = end($this->stack)->nodeName; - - if(in_array($node, $elements)) { - break; - } else { - array_pop($this->stack); - } - } - } - - private function resetInsertionMode() { - /* 1. Let last be false. */ - $last = false; - $leng = count($this->stack); - - for($n = $leng - 1; $n >= 0; $n--) { - /* 2. Let node be the last node in the stack of open elements. */ - $node = $this->stack[$n]; - - /* 3. If node is the first node in the stack of open elements, then - set last to true. If the element whose innerHTML attribute is being - set is neither a td element nor a th element, then set node to the - element whose innerHTML attribute is being set. (innerHTML case) */ - if($this->stack[0]->isSameNode($node)) { - $last = true; - } - - /* 4. If node is a select element, then switch the insertion mode to - "in select" and abort these steps. (innerHTML case) */ - if($node->nodeName === 'select') { - $this->mode = self::IN_SELECT; - break; - - /* 5. If node is a td or th element, then switch the insertion mode - to "in cell" and abort these steps. */ - } elseif($node->nodeName === 'td' || $node->nodeName === 'th') { - $this->mode = self::IN_CELL; - break; - - /* 6. If node is a tr element, then switch the insertion mode to - "in row" and abort these steps. */ - } elseif($node->nodeName === 'tr') { - $this->mode = self::IN_ROW; - break; - - /* 7. If node is a tbody, thead, or tfoot element, then switch the - insertion mode to "in table body" and abort these steps. */ - } elseif(in_array($node->nodeName, array('tbody', 'thead', 'tfoot'))) { - $this->mode = self::IN_TBODY; - break; - - /* 8. If node is a caption element, then switch the insertion mode - to "in caption" and abort these steps. */ - } elseif($node->nodeName === 'caption') { - $this->mode = self::IN_CAPTION; - break; - - /* 9. If node is a colgroup element, then switch the insertion mode - to "in column group" and abort these steps. (innerHTML case) */ - } elseif($node->nodeName === 'colgroup') { - $this->mode = self::IN_CGROUP; - break; - - /* 10. If node is a table element, then switch the insertion mode - to "in table" and abort these steps. */ - } elseif($node->nodeName === 'table') { - $this->mode = self::IN_TABLE; - break; - - /* 11. If node is a head element, then switch the insertion mode - to "in body" ("in body"! not "in head"!) and abort these steps. - (innerHTML case) */ - } elseif($node->nodeName === 'head') { - $this->mode = self::IN_BODY; - break; - - /* 12. If node is a body element, then switch the insertion mode to - "in body" and abort these steps. */ - } elseif($node->nodeName === 'body') { - $this->mode = self::IN_BODY; - break; - - /* 13. If node is a frameset element, then switch the insertion - mode to "in frameset" and abort these steps. (innerHTML case) */ - } elseif($node->nodeName === 'frameset') { - $this->mode = self::IN_FRAME; - break; - - /* 14. If node is an html element, then: if the head element - pointer is null, switch the insertion mode to "before head", - otherwise, switch the insertion mode to "after head". In either - case, abort these steps. (innerHTML case) */ - } elseif($node->nodeName === 'html') { - $this->mode = ($this->head_pointer === null) - ? self::BEFOR_HEAD - : self::AFTER_HEAD; - - break; - - /* 15. If last is true, then set the insertion mode to "in body" - and abort these steps. (innerHTML case) */ - } elseif($last) { - $this->mode = self::IN_BODY; - break; - } - } - } - - private function closeCell() { - /* If the stack of open elements has a td or th element in table scope, - then act as if an end tag token with that tag name had been seen. */ - foreach(array('td', 'th') as $cell) { - if($this->elementInScope($cell, true)) { - $this->inCell(array( - 'name' => $cell, - 'type' => HTML5::ENDTAG - )); - - break; - } - } - } - - public function save() { - return $this->dom; - } -} - diff --git a/modules/gallery/lib/HTMLPurifier/HTMLPurifier/PercentEncoder.php b/modules/gallery/lib/HTMLPurifier/HTMLPurifier/PercentEncoder.php deleted file mode 100644 index a8ad230d..00000000 --- a/modules/gallery/lib/HTMLPurifier/HTMLPurifier/PercentEncoder.php +++ /dev/null @@ -1,98 +0,0 @@ -preserve[$i] = true; // digits - for ($i = 65; $i <= 90; $i++) $this->preserve[$i] = true; // upper-case - for ($i = 97; $i <= 122; $i++) $this->preserve[$i] = true; // lower-case - $this->preserve[45] = true; // Dash - - $this->preserve[46] = true; // Period . - $this->preserve[95] = true; // Underscore _ - $this->preserve[126]= true; // Tilde ~ - - // extra letters not to escape - if ($preserve !== false) { - for ($i = 0, $c = strlen($preserve); $i < $c; $i++) { - $this->preserve[ord($preserve[$i])] = true; - } - } - } - - /** - * Our replacement for urlencode, it encodes all non-reserved characters, - * as well as any extra characters that were instructed to be preserved. - * @note - * Assumes that the string has already been normalized, making any - * and all percent escape sequences valid. Percents will not be - * re-escaped, regardless of their status in $preserve - * @param $string String to be encoded - * @return Encoded string. - */ - public function encode($string) { - $ret = ''; - for ($i = 0, $c = strlen($string); $i < $c; $i++) { - if ($string[$i] !== '%' && !isset($this->preserve[$int = ord($string[$i])]) ) { - $ret .= '%' . sprintf('%02X', $int); - } else { - $ret .= $string[$i]; - } - } - return $ret; - } - - /** - * Fix up percent-encoding by decoding unreserved characters and normalizing. - * @warning This function is affected by $preserve, even though the - * usual desired behavior is for this not to preserve those - * characters. Be careful when reusing instances of PercentEncoder! - * @param $string String to normalize - */ - public function normalize($string) { - if ($string == '') return ''; - $parts = explode('%', $string); - $ret = array_shift($parts); - foreach ($parts as $part) { - $length = strlen($part); - if ($length < 2) { - $ret .= '%25' . $part; - continue; - } - $encoding = substr($part, 0, 2); - $text = substr($part, 2); - if (!ctype_xdigit($encoding)) { - $ret .= '%25' . $part; - continue; - } - $int = hexdec($encoding); - if (isset($this->preserve[$int])) { - $ret .= chr($int) . $text; - continue; - } - $encoding = strtoupper($encoding); - $ret .= '%' . $encoding . $text; - } - return $ret; - } - -} - -// vim: et sw=4 sts=4 diff --git a/modules/gallery/lib/HTMLPurifier/HTMLPurifier/Printer.php b/modules/gallery/lib/HTMLPurifier/HTMLPurifier/Printer.php deleted file mode 100644 index a0d4a0fd..00000000 --- a/modules/gallery/lib/HTMLPurifier/HTMLPurifier/Printer.php +++ /dev/null @@ -1,176 +0,0 @@ -getAll(); - $context = new HTMLPurifier_Context(); - $this->generator = new HTMLPurifier_Generator($config, $context); - } - - /** - * Main function that renders object or aspect of that object - * @note Parameters vary depending on printer - */ - // function render() {} - - /** - * Returns a start tag - * @param $tag Tag name - * @param $attr Attribute array - */ - protected function start($tag, $attr = array()) { - return $this->generator->generateFromToken( - new HTMLPurifier_Token_Start($tag, $attr ? $attr : array()) - ); - } - - /** - * Returns an end teg - * @param $tag Tag name - */ - protected function end($tag) { - return $this->generator->generateFromToken( - new HTMLPurifier_Token_End($tag) - ); - } - - /** - * Prints a complete element with content inside - * @param $tag Tag name - * @param $contents Element contents - * @param $attr Tag attributes - * @param $escape Bool whether or not to escape contents - */ - protected function element($tag, $contents, $attr = array(), $escape = true) { - return $this->start($tag, $attr) . - ($escape ? $this->escape($contents) : $contents) . - $this->end($tag); - } - - protected function elementEmpty($tag, $attr = array()) { - return $this->generator->generateFromToken( - new HTMLPurifier_Token_Empty($tag, $attr) - ); - } - - protected function text($text) { - return $this->generator->generateFromToken( - new HTMLPurifier_Token_Text($text) - ); - } - - /** - * Prints a simple key/value row in a table. - * @param $name Key - * @param $value Value - */ - protected function row($name, $value) { - if (is_bool($value)) $value = $value ? 'On' : 'Off'; - return - $this->start('tr') . "\n" . - $this->element('th', $name) . "\n" . - $this->element('td', $value) . "\n" . - $this->end('tr') - ; - } - - /** - * Escapes a string for HTML output. - * @param $string String to escape - */ - protected function escape($string) { - $string = HTMLPurifier_Encoder::cleanUTF8($string); - $string = htmlspecialchars($string, ENT_COMPAT, 'UTF-8'); - return $string; - } - - /** - * Takes a list of strings and turns them into a single list - * @param $array List of strings - * @param $polite Bool whether or not to add an end before the last - */ - protected function listify($array, $polite = false) { - if (empty($array)) return 'None'; - $ret = ''; - $i = count($array); - foreach ($array as $value) { - $i--; - $ret .= $value; - if ($i > 0 && !($polite && $i == 1)) $ret .= ', '; - if ($polite && $i == 1) $ret .= 'and '; - } - return $ret; - } - - /** - * Retrieves the class of an object without prefixes, as well as metadata - * @param $obj Object to determine class of - * @param $prefix Further prefix to remove - */ - protected function getClass($obj, $sec_prefix = '') { - static $five = null; - if ($five === null) $five = version_compare(PHP_VERSION, '5', '>='); - $prefix = 'HTMLPurifier_' . $sec_prefix; - if (!$five) $prefix = strtolower($prefix); - $class = str_replace($prefix, '', get_class($obj)); - $lclass = strtolower($class); - $class .= '('; - switch ($lclass) { - case 'enum': - $values = array(); - foreach ($obj->valid_values as $value => $bool) { - $values[] = $value; - } - $class .= implode(', ', $values); - break; - case 'css_composite': - $values = array(); - foreach ($obj->defs as $def) { - $values[] = $this->getClass($def, $sec_prefix); - } - $class .= implode(', ', $values); - break; - case 'css_multiple': - $class .= $this->getClass($obj->single, $sec_prefix) . ', '; - $class .= $obj->max; - break; - case 'css_denyelementdecorator': - $class .= $this->getClass($obj->def, $sec_prefix) . ', '; - $class .= $obj->element; - break; - case 'css_importantdecorator': - $class .= $this->getClass($obj->def, $sec_prefix); - if ($obj->allow) $class .= ', !important'; - break; - } - $class .= ')'; - return $class; - } - -} - -// vim: et sw=4 sts=4 diff --git a/modules/gallery/lib/HTMLPurifier/HTMLPurifier/Printer/CSSDefinition.php b/modules/gallery/lib/HTMLPurifier/HTMLPurifier/Printer/CSSDefinition.php deleted file mode 100644 index 0be17df7..00000000 --- a/modules/gallery/lib/HTMLPurifier/HTMLPurifier/Printer/CSSDefinition.php +++ /dev/null @@ -1,38 +0,0 @@ -def = $config->getCSSDefinition(); - $ret = ''; - - $ret .= $this->start('div', array('class' => 'HTMLPurifier_Printer')); - $ret .= $this->start('table'); - - $ret .= $this->element('caption', 'Properties ($info)'); - - $ret .= $this->start('thead'); - $ret .= $this->start('tr'); - $ret .= $this->element('th', 'Property', array('class' => 'heavy')); - $ret .= $this->element('th', 'Definition', array('class' => 'heavy', 'style' => 'width:auto;')); - $ret .= $this->end('tr'); - $ret .= $this->end('thead'); - - ksort($this->def->info); - foreach ($this->def->info as $property => $obj) { - $name = $this->getClass($obj, 'AttrDef_'); - $ret .= $this->row($property, $name); - } - - $ret .= $this->end('table'); - $ret .= $this->end('div'); - - return $ret; - } - -} - -// vim: et sw=4 sts=4 diff --git a/modules/gallery/lib/HTMLPurifier/HTMLPurifier/Printer/ConfigForm.css b/modules/gallery/lib/HTMLPurifier/HTMLPurifier/Printer/ConfigForm.css deleted file mode 100644 index 3ff1a88a..00000000 --- a/modules/gallery/lib/HTMLPurifier/HTMLPurifier/Printer/ConfigForm.css +++ /dev/null @@ -1,10 +0,0 @@ - -.hp-config {} - -.hp-config tbody th {text-align:right; padding-right:0.5em;} -.hp-config thead, .hp-config .namespace {background:#3C578C; color:#FFF;} -.hp-config .namespace th {text-align:center;} -.hp-config .verbose {display:none;} -.hp-config .controls {text-align:center;} - -/* vim: et sw=4 sts=4 */ diff --git a/modules/gallery/lib/HTMLPurifier/HTMLPurifier/Printer/ConfigForm.js b/modules/gallery/lib/HTMLPurifier/HTMLPurifier/Printer/ConfigForm.js deleted file mode 100644 index cba00c9b..00000000 --- a/modules/gallery/lib/HTMLPurifier/HTMLPurifier/Printer/ConfigForm.js +++ /dev/null @@ -1,5 +0,0 @@ -function toggleWriteability(id_of_patient, checked) { - document.getElementById(id_of_patient).disabled = checked; -} - -// vim: et sw=4 sts=4 diff --git a/modules/gallery/lib/HTMLPurifier/HTMLPurifier/Printer/ConfigForm.php b/modules/gallery/lib/HTMLPurifier/HTMLPurifier/Printer/ConfigForm.php deleted file mode 100644 index 4d391992..00000000 --- a/modules/gallery/lib/HTMLPurifier/HTMLPurifier/Printer/ConfigForm.php +++ /dev/null @@ -1,368 +0,0 @@ -docURL = $doc_url; - $this->name = $name; - $this->compress = $compress; - // initialize sub-printers - $this->fields[0] = new HTMLPurifier_Printer_ConfigForm_default(); - $this->fields[HTMLPurifier_VarParser::BOOL] = new HTMLPurifier_Printer_ConfigForm_bool(); - } - - /** - * Sets default column and row size for textareas in sub-printers - * @param $cols Integer columns of textarea, null to use default - * @param $rows Integer rows of textarea, null to use default - */ - public function setTextareaDimensions($cols = null, $rows = null) { - if ($cols) $this->fields['default']->cols = $cols; - if ($rows) $this->fields['default']->rows = $rows; - } - - /** - * Retrieves styling, in case it is not accessible by webserver - */ - public static function getCSS() { - return file_get_contents(HTMLPURIFIER_PREFIX . '/HTMLPurifier/Printer/ConfigForm.css'); - } - - /** - * Retrieves JavaScript, in case it is not accessible by webserver - */ - public static function getJavaScript() { - return file_get_contents(HTMLPURIFIER_PREFIX . '/HTMLPurifier/Printer/ConfigForm.js'); - } - - /** - * Returns HTML output for a configuration form - * @param $config Configuration object of current form state, or an array - * where [0] has an HTML namespace and [1] is being rendered. - * @param $allowed Optional namespace(s) and directives to restrict form to. - */ - public function render($config, $allowed = true, $render_controls = true) { - if (is_array($config) && isset($config[0])) { - $gen_config = $config[0]; - $config = $config[1]; - } else { - $gen_config = $config; - } - - $this->config = $config; - $this->genConfig = $gen_config; - $this->prepareGenerator($gen_config); - - $allowed = HTMLPurifier_Config::getAllowedDirectivesForForm($allowed, $config->def); - $all = array(); - foreach ($allowed as $key) { - list($ns, $directive) = $key; - $all[$ns][$directive] = $config->get($ns .'.'. $directive); - } - - $ret = ''; - $ret .= $this->start('table', array('class' => 'hp-config')); - $ret .= $this->start('thead'); - $ret .= $this->start('tr'); - $ret .= $this->element('th', 'Directive', array('class' => 'hp-directive')); - $ret .= $this->element('th', 'Value', array('class' => 'hp-value')); - $ret .= $this->end('tr'); - $ret .= $this->end('thead'); - foreach ($all as $ns => $directives) { - $ret .= $this->renderNamespace($ns, $directives); - } - if ($render_controls) { - $ret .= $this->start('tbody'); - $ret .= $this->start('tr'); - $ret .= $this->start('td', array('colspan' => 2, 'class' => 'controls')); - $ret .= $this->elementEmpty('input', array('type' => 'submit', 'value' => 'Submit')); - $ret .= '[Reset]'; - $ret .= $this->end('td'); - $ret .= $this->end('tr'); - $ret .= $this->end('tbody'); - } - $ret .= $this->end('table'); - return $ret; - } - - /** - * Renders a single namespace - * @param $ns String namespace name - * @param $directive Associative array of directives to values - */ - protected function renderNamespace($ns, $directives) { - $ret = ''; - $ret .= $this->start('tbody', array('class' => 'namespace')); - $ret .= $this->start('tr'); - $ret .= $this->element('th', $ns, array('colspan' => 2)); - $ret .= $this->end('tr'); - $ret .= $this->end('tbody'); - $ret .= $this->start('tbody'); - foreach ($directives as $directive => $value) { - $ret .= $this->start('tr'); - $ret .= $this->start('th'); - if ($this->docURL) { - $url = str_replace('%s', urlencode("$ns.$directive"), $this->docURL); - $ret .= $this->start('a', array('href' => $url)); - } - $attr = array('for' => "{$this->name}:$ns.$directive"); - - // crop directive name if it's too long - if (!$this->compress || (strlen($directive) < $this->compress)) { - $directive_disp = $directive; - } else { - $directive_disp = substr($directive, 0, $this->compress - 2) . '...'; - $attr['title'] = $directive; - } - - $ret .= $this->element( - 'label', - $directive_disp, - // component printers must create an element with this id - $attr - ); - if ($this->docURL) $ret .= $this->end('a'); - $ret .= $this->end('th'); - - $ret .= $this->start('td'); - $def = $this->config->def->info["$ns.$directive"]; - if (is_int($def)) { - $allow_null = $def < 0; - $type = abs($def); - } else { - $type = $def->type; - $allow_null = isset($def->allow_null); - } - if (!isset($this->fields[$type])) $type = 0; // default - $type_obj = $this->fields[$type]; - if ($allow_null) { - $type_obj = new HTMLPurifier_Printer_ConfigForm_NullDecorator($type_obj); - } - $ret .= $type_obj->render($ns, $directive, $value, $this->name, array($this->genConfig, $this->config)); - $ret .= $this->end('td'); - $ret .= $this->end('tr'); - } - $ret .= $this->end('tbody'); - return $ret; - } - -} - -/** - * Printer decorator for directives that accept null - */ -class HTMLPurifier_Printer_ConfigForm_NullDecorator extends HTMLPurifier_Printer { - /** - * Printer being decorated - */ - protected $obj; - /** - * @param $obj Printer to decorate - */ - public function __construct($obj) { - parent::__construct(); - $this->obj = $obj; - } - public function render($ns, $directive, $value, $name, $config) { - if (is_array($config) && isset($config[0])) { - $gen_config = $config[0]; - $config = $config[1]; - } else { - $gen_config = $config; - } - $this->prepareGenerator($gen_config); - - $ret = ''; - $ret .= $this->start('label', array('for' => "$name:Null_$ns.$directive")); - $ret .= $this->element('span', "$ns.$directive:", array('class' => 'verbose')); - $ret .= $this->text(' Null/Disabled'); - $ret .= $this->end('label'); - $attr = array( - 'type' => 'checkbox', - 'value' => '1', - 'class' => 'null-toggle', - 'name' => "$name"."[Null_$ns.$directive]", - 'id' => "$name:Null_$ns.$directive", - 'onclick' => "toggleWriteability('$name:$ns.$directive',checked)" // INLINE JAVASCRIPT!!!! - ); - if ($this->obj instanceof HTMLPurifier_Printer_ConfigForm_bool) { - // modify inline javascript slightly - $attr['onclick'] = "toggleWriteability('$name:Yes_$ns.$directive',checked);toggleWriteability('$name:No_$ns.$directive',checked)"; - } - if ($value === null) $attr['checked'] = 'checked'; - $ret .= $this->elementEmpty('input', $attr); - $ret .= $this->text(' or '); - $ret .= $this->elementEmpty('br'); - $ret .= $this->obj->render($ns, $directive, $value, $name, array($gen_config, $config)); - return $ret; - } -} - -/** - * Swiss-army knife configuration form field printer - */ -class HTMLPurifier_Printer_ConfigForm_default extends HTMLPurifier_Printer { - public $cols = 18; - public $rows = 5; - public function render($ns, $directive, $value, $name, $config) { - if (is_array($config) && isset($config[0])) { - $gen_config = $config[0]; - $config = $config[1]; - } else { - $gen_config = $config; - } - $this->prepareGenerator($gen_config); - // this should probably be split up a little - $ret = ''; - $def = $config->def->info["$ns.$directive"]; - if (is_int($def)) { - $type = abs($def); - } else { - $type = $def->type; - } - if (is_array($value)) { - switch ($type) { - case HTMLPurifier_VarParser::LOOKUP: - $array = $value; - $value = array(); - foreach ($array as $val => $b) { - $value[] = $val; - } - case HTMLPurifier_VarParser::ALIST: - $value = implode(PHP_EOL, $value); - break; - case HTMLPurifier_VarParser::HASH: - $nvalue = ''; - foreach ($value as $i => $v) { - $nvalue .= "$i:$v" . PHP_EOL; - } - $value = $nvalue; - break; - default: - $value = ''; - } - } - if ($type === HTMLPurifier_VarParser::MIXED) { - return 'Not supported'; - $value = serialize($value); - } - $attr = array( - 'name' => "$name"."[$ns.$directive]", - 'id' => "$name:$ns.$directive" - ); - if ($value === null) $attr['disabled'] = 'disabled'; - if (isset($def->allowed)) { - $ret .= $this->start('select', $attr); - foreach ($def->allowed as $val => $b) { - $attr = array(); - if ($value == $val) $attr['selected'] = 'selected'; - $ret .= $this->element('option', $val, $attr); - } - $ret .= $this->end('select'); - } elseif ( - $type === HTMLPurifier_VarParser::TEXT || - $type === HTMLPurifier_VarParser::ITEXT || - $type === HTMLPurifier_VarParser::ALIST || - $type === HTMLPurifier_VarParser::HASH || - $type === HTMLPurifier_VarParser::LOOKUP - ) { - $attr['cols'] = $this->cols; - $attr['rows'] = $this->rows; - $ret .= $this->start('textarea', $attr); - $ret .= $this->text($value); - $ret .= $this->end('textarea'); - } else { - $attr['value'] = $value; - $attr['type'] = 'text'; - $ret .= $this->elementEmpty('input', $attr); - } - return $ret; - } -} - -/** - * Bool form field printer - */ -class HTMLPurifier_Printer_ConfigForm_bool extends HTMLPurifier_Printer { - public function render($ns, $directive, $value, $name, $config) { - if (is_array($config) && isset($config[0])) { - $gen_config = $config[0]; - $config = $config[1]; - } else { - $gen_config = $config; - } - $this->prepareGenerator($gen_config); - $ret = ''; - $ret .= $this->start('div', array('id' => "$name:$ns.$directive")); - - $ret .= $this->start('label', array('for' => "$name:Yes_$ns.$directive")); - $ret .= $this->element('span', "$ns.$directive:", array('class' => 'verbose')); - $ret .= $this->text(' Yes'); - $ret .= $this->end('label'); - - $attr = array( - 'type' => 'radio', - 'name' => "$name"."[$ns.$directive]", - 'id' => "$name:Yes_$ns.$directive", - 'value' => '1' - ); - if ($value === true) $attr['checked'] = 'checked'; - if ($value === null) $attr['disabled'] = 'disabled'; - $ret .= $this->elementEmpty('input', $attr); - - $ret .= $this->start('label', array('for' => "$name:No_$ns.$directive")); - $ret .= $this->element('span', "$ns.$directive:", array('class' => 'verbose')); - $ret .= $this->text(' No'); - $ret .= $this->end('label'); - - $attr = array( - 'type' => 'radio', - 'name' => "$name"."[$ns.$directive]", - 'id' => "$name:No_$ns.$directive", - 'value' => '0' - ); - if ($value === false) $attr['checked'] = 'checked'; - if ($value === null) $attr['disabled'] = 'disabled'; - $ret .= $this->elementEmpty('input', $attr); - - $ret .= $this->end('div'); - - return $ret; - } -} - -// vim: et sw=4 sts=4 diff --git a/modules/gallery/lib/HTMLPurifier/HTMLPurifier/Printer/HTMLDefinition.php b/modules/gallery/lib/HTMLPurifier/HTMLPurifier/Printer/HTMLDefinition.php deleted file mode 100644 index 556caf57..00000000 --- a/modules/gallery/lib/HTMLPurifier/HTMLPurifier/Printer/HTMLDefinition.php +++ /dev/null @@ -1,272 +0,0 @@ -config =& $config; - - $this->def = $config->getHTMLDefinition(); - - $ret .= $this->start('div', array('class' => 'HTMLPurifier_Printer')); - - $ret .= $this->renderDoctype(); - $ret .= $this->renderEnvironment(); - $ret .= $this->renderContentSets(); - $ret .= $this->renderInfo(); - - $ret .= $this->end('div'); - - return $ret; - } - - /** - * Renders the Doctype table - */ - protected function renderDoctype() { - $doctype = $this->def->doctype; - $ret = ''; - $ret .= $this->start('table'); - $ret .= $this->element('caption', 'Doctype'); - $ret .= $this->row('Name', $doctype->name); - $ret .= $this->row('XML', $doctype->xml ? 'Yes' : 'No'); - $ret .= $this->row('Default Modules', implode($doctype->modules, ', ')); - $ret .= $this->row('Default Tidy Modules', implode($doctype->tidyModules, ', ')); - $ret .= $this->end('table'); - return $ret; - } - - - /** - * Renders environment table, which is miscellaneous info - */ - protected function renderEnvironment() { - $def = $this->def; - - $ret = ''; - - $ret .= $this->start('table'); - $ret .= $this->element('caption', 'Environment'); - - $ret .= $this->row('Parent of fragment', $def->info_parent); - $ret .= $this->renderChildren($def->info_parent_def->child); - $ret .= $this->row('Block wrap name', $def->info_block_wrapper); - - $ret .= $this->start('tr'); - $ret .= $this->element('th', 'Global attributes'); - $ret .= $this->element('td', $this->listifyAttr($def->info_global_attr),0,0); - $ret .= $this->end('tr'); - - $ret .= $this->start('tr'); - $ret .= $this->element('th', 'Tag transforms'); - $list = array(); - foreach ($def->info_tag_transform as $old => $new) { - $new = $this->getClass($new, 'TagTransform_'); - $list[] = "<$old> with $new"; - } - $ret .= $this->element('td', $this->listify($list)); - $ret .= $this->end('tr'); - - $ret .= $this->start('tr'); - $ret .= $this->element('th', 'Pre-AttrTransform'); - $ret .= $this->element('td', $this->listifyObjectList($def->info_attr_transform_pre)); - $ret .= $this->end('tr'); - - $ret .= $this->start('tr'); - $ret .= $this->element('th', 'Post-AttrTransform'); - $ret .= $this->element('td', $this->listifyObjectList($def->info_attr_transform_post)); - $ret .= $this->end('tr'); - - $ret .= $this->end('table'); - return $ret; - } - - /** - * Renders the Content Sets table - */ - protected function renderContentSets() { - $ret = ''; - $ret .= $this->start('table'); - $ret .= $this->element('caption', 'Content Sets'); - foreach ($this->def->info_content_sets as $name => $lookup) { - $ret .= $this->heavyHeader($name); - $ret .= $this->start('tr'); - $ret .= $this->element('td', $this->listifyTagLookup($lookup)); - $ret .= $this->end('tr'); - } - $ret .= $this->end('table'); - return $ret; - } - - /** - * Renders the Elements ($info) table - */ - protected function renderInfo() { - $ret = ''; - $ret .= $this->start('table'); - $ret .= $this->element('caption', 'Elements ($info)'); - ksort($this->def->info); - $ret .= $this->heavyHeader('Allowed tags', 2); - $ret .= $this->start('tr'); - $ret .= $this->element('td', $this->listifyTagLookup($this->def->info), array('colspan' => 2)); - $ret .= $this->end('tr'); - foreach ($this->def->info as $name => $def) { - $ret .= $this->start('tr'); - $ret .= $this->element('th', "<$name>", array('class'=>'heavy', 'colspan' => 2)); - $ret .= $this->end('tr'); - $ret .= $this->start('tr'); - $ret .= $this->element('th', 'Inline content'); - $ret .= $this->element('td', $def->descendants_are_inline ? 'Yes' : 'No'); - $ret .= $this->end('tr'); - if (!empty($def->excludes)) { - $ret .= $this->start('tr'); - $ret .= $this->element('th', 'Excludes'); - $ret .= $this->element('td', $this->listifyTagLookup($def->excludes)); - $ret .= $this->end('tr'); - } - if (!empty($def->attr_transform_pre)) { - $ret .= $this->start('tr'); - $ret .= $this->element('th', 'Pre-AttrTransform'); - $ret .= $this->element('td', $this->listifyObjectList($def->attr_transform_pre)); - $ret .= $this->end('tr'); - } - if (!empty($def->attr_transform_post)) { - $ret .= $this->start('tr'); - $ret .= $this->element('th', 'Post-AttrTransform'); - $ret .= $this->element('td', $this->listifyObjectList($def->attr_transform_post)); - $ret .= $this->end('tr'); - } - if (!empty($def->auto_close)) { - $ret .= $this->start('tr'); - $ret .= $this->element('th', 'Auto closed by'); - $ret .= $this->element('td', $this->listifyTagLookup($def->auto_close)); - $ret .= $this->end('tr'); - } - $ret .= $this->start('tr'); - $ret .= $this->element('th', 'Allowed attributes'); - $ret .= $this->element('td',$this->listifyAttr($def->attr), array(), 0); - $ret .= $this->end('tr'); - - if (!empty($def->required_attr)) { - $ret .= $this->row('Required attributes', $this->listify($def->required_attr)); - } - - $ret .= $this->renderChildren($def->child); - } - $ret .= $this->end('table'); - return $ret; - } - - /** - * Renders a row describing the allowed children of an element - * @param $def HTMLPurifier_ChildDef of pertinent element - */ - protected function renderChildren($def) { - $context = new HTMLPurifier_Context(); - $ret = ''; - $ret .= $this->start('tr'); - $elements = array(); - $attr = array(); - if (isset($def->elements)) { - if ($def->type == 'strictblockquote') { - $def->validateChildren(array(), $this->config, $context); - } - $elements = $def->elements; - } - if ($def->type == 'chameleon') { - $attr['rowspan'] = 2; - } elseif ($def->type == 'empty') { - $elements = array(); - } elseif ($def->type == 'table') { - $elements = array_flip(array('col', 'caption', 'colgroup', 'thead', - 'tfoot', 'tbody', 'tr')); - } - $ret .= $this->element('th', 'Allowed children', $attr); - - if ($def->type == 'chameleon') { - - $ret .= $this->element('td', - 'Block: ' . - $this->escape($this->listifyTagLookup($def->block->elements)),0,0); - $ret .= $this->end('tr'); - $ret .= $this->start('tr'); - $ret .= $this->element('td', - 'Inline: ' . - $this->escape($this->listifyTagLookup($def->inline->elements)),0,0); - - } elseif ($def->type == 'custom') { - - $ret .= $this->element('td', ''.ucfirst($def->type).': ' . - $def->dtd_regex); - - } else { - $ret .= $this->element('td', - ''.ucfirst($def->type).': ' . - $this->escape($this->listifyTagLookup($elements)),0,0); - } - $ret .= $this->end('tr'); - return $ret; - } - - /** - * Listifies a tag lookup table. - * @param $array Tag lookup array in form of array('tagname' => true) - */ - protected function listifyTagLookup($array) { - ksort($array); - $list = array(); - foreach ($array as $name => $discard) { - if ($name !== '#PCDATA' && !isset($this->def->info[$name])) continue; - $list[] = $name; - } - return $this->listify($list); - } - - /** - * Listifies a list of objects by retrieving class names and internal state - * @param $array List of objects - * @todo Also add information about internal state - */ - protected function listifyObjectList($array) { - ksort($array); - $list = array(); - foreach ($array as $discard => $obj) { - $list[] = $this->getClass($obj, 'AttrTransform_'); - } - return $this->listify($list); - } - - /** - * Listifies a hash of attributes to AttrDef classes - * @param $array Array hash in form of array('attrname' => HTMLPurifier_AttrDef) - */ - protected function listifyAttr($array) { - ksort($array); - $list = array(); - foreach ($array as $name => $obj) { - if ($obj === false) continue; - $list[] = "$name = " . $this->getClass($obj, 'AttrDef_') . ''; - } - return $this->listify($list); - } - - /** - * Creates a heavy header row - */ - protected function heavyHeader($text, $num = 1) { - $ret = ''; - $ret .= $this->start('tr'); - $ret .= $this->element('th', $text, array('colspan' => $num, 'class' => 'heavy')); - $ret .= $this->end('tr'); - return $ret; - } - -} - -// vim: et sw=4 sts=4 diff --git a/modules/gallery/lib/HTMLPurifier/HTMLPurifier/PropertyList.php b/modules/gallery/lib/HTMLPurifier/HTMLPurifier/PropertyList.php deleted file mode 100644 index f3e2947c..00000000 --- a/modules/gallery/lib/HTMLPurifier/HTMLPurifier/PropertyList.php +++ /dev/null @@ -1,86 +0,0 @@ -parent = $parent; - } - - /** - * Recursively retrieves the value for a key - */ - public function get($name) { - if ($this->has($name)) return $this->data[$name]; - // possible performance bottleneck, convert to iterative if necessary - if ($this->parent) return $this->parent->get($name); - throw new HTMLPurifier_Exception("Key '$name' not found"); - } - - /** - * Sets the value of a key, for this plist - */ - public function set($name, $value) { - $this->data[$name] = $value; - } - - /** - * Returns true if a given key exists - */ - public function has($name) { - return array_key_exists($name, $this->data); - } - - /** - * Resets a value to the value of it's parent, usually the default. If - * no value is specified, the entire plist is reset. - */ - public function reset($name = null) { - if ($name == null) $this->data = array(); - else unset($this->data[$name]); - } - - /** - * Squashes this property list and all of its property lists into a single - * array, and returns the array. This value is cached by default. - * @param $force If true, ignores the cache and regenerates the array. - */ - public function squash($force = false) { - if ($this->cache !== null && !$force) return $this->cache; - if ($this->parent) { - return $this->cache = array_merge($this->parent->squash($force), $this->data); - } else { - return $this->cache = $this->data; - } - } - - /** - * Returns the parent plist. - */ - public function getParent() { - return $this->parent; - } - - /** - * Sets the parent plist. - */ - public function setParent($plist) { - $this->parent = $plist; - } -} - -// vim: et sw=4 sts=4 diff --git a/modules/gallery/lib/HTMLPurifier/HTMLPurifier/PropertyListIterator.php b/modules/gallery/lib/HTMLPurifier/HTMLPurifier/PropertyListIterator.php deleted file mode 100644 index 7fa2088e..00000000 --- a/modules/gallery/lib/HTMLPurifier/HTMLPurifier/PropertyListIterator.php +++ /dev/null @@ -1,32 +0,0 @@ -l = strlen($filter); - $this->filter = $filter; - } - - public function accept() { - $key = $this->getInnerIterator()->key(); - if( strncmp($key, $this->filter, $this->l) !== 0 ) { - return false; - } - return true; - } - -} - -// vim: et sw=4 sts=4 diff --git a/modules/gallery/lib/HTMLPurifier/HTMLPurifier/Strategy.php b/modules/gallery/lib/HTMLPurifier/HTMLPurifier/Strategy.php deleted file mode 100644 index e975e2c8..00000000 --- a/modules/gallery/lib/HTMLPurifier/HTMLPurifier/Strategy.php +++ /dev/null @@ -1,26 +0,0 @@ -strategies as $strategy) { - $tokens = $strategy->execute($tokens, $config, $context); - } - return $tokens; - } - -} - -// vim: et sw=4 sts=4 diff --git a/modules/gallery/lib/HTMLPurifier/HTMLPurifier/Strategy/Core.php b/modules/gallery/lib/HTMLPurifier/HTMLPurifier/Strategy/Core.php deleted file mode 100644 index c7d3c79c..00000000 --- a/modules/gallery/lib/HTMLPurifier/HTMLPurifier/Strategy/Core.php +++ /dev/null @@ -1,18 +0,0 @@ -strategies[] = new HTMLPurifier_Strategy_RemoveForeignElements(); - $this->strategies[] = new HTMLPurifier_Strategy_MakeWellFormed(); - $this->strategies[] = new HTMLPurifier_Strategy_FixNesting(); - $this->strategies[] = new HTMLPurifier_Strategy_ValidateAttributes(); - } - -} - -// vim: et sw=4 sts=4 diff --git a/modules/gallery/lib/HTMLPurifier/HTMLPurifier/Strategy/FixNesting.php b/modules/gallery/lib/HTMLPurifier/HTMLPurifier/Strategy/FixNesting.php deleted file mode 100644 index dc4ef88b..00000000 --- a/modules/gallery/lib/HTMLPurifier/HTMLPurifier/Strategy/FixNesting.php +++ /dev/null @@ -1,328 +0,0 @@ -getHTMLDefinition(); - - // insert implicit "parent" node, will be removed at end. - // DEFINITION CALL - $parent_name = $definition->info_parent; - array_unshift($tokens, new HTMLPurifier_Token_Start($parent_name)); - $tokens[] = new HTMLPurifier_Token_End($parent_name); - - // setup the context variable 'IsInline', for chameleon processing - // is 'false' when we are not inline, 'true' when it must always - // be inline, and an integer when it is inline for a certain - // branch of the document tree - $is_inline = $definition->info_parent_def->descendants_are_inline; - $context->register('IsInline', $is_inline); - - // setup error collector - $e =& $context->get('ErrorCollector', true); - - //####################################################################// - // Loop initialization - - // stack that contains the indexes of all parents, - // $stack[count($stack)-1] being the current parent - $stack = array(); - - // stack that contains all elements that are excluded - // it is organized by parent elements, similar to $stack, - // but it is only populated when an element with exclusions is - // processed, i.e. there won't be empty exclusions. - $exclude_stack = array(); - - // variable that contains the start token while we are processing - // nodes. This enables error reporting to do its job - $start_token = false; - $context->register('CurrentToken', $start_token); - - //####################################################################// - // Loop - - // iterate through all start nodes. Determining the start node - // is complicated so it has been omitted from the loop construct - for ($i = 0, $size = count($tokens) ; $i < $size; ) { - - //################################################################// - // Gather information on children - - // child token accumulator - $child_tokens = array(); - - // scroll to the end of this node, report number, and collect - // all children - for ($j = $i, $depth = 0; ; $j++) { - if ($tokens[$j] instanceof HTMLPurifier_Token_Start) { - $depth++; - // skip token assignment on first iteration, this is the - // token we currently are on - if ($depth == 1) continue; - } elseif ($tokens[$j] instanceof HTMLPurifier_Token_End) { - $depth--; - // skip token assignment on last iteration, this is the - // end token of the token we're currently on - if ($depth == 0) break; - } - $child_tokens[] = $tokens[$j]; - } - - // $i is index of start token - // $j is index of end token - - $start_token = $tokens[$i]; // to make token available via CurrentToken - - //################################################################// - // Gather information on parent - - // calculate parent information - if ($count = count($stack)) { - $parent_index = $stack[$count-1]; - $parent_name = $tokens[$parent_index]->name; - if ($parent_index == 0) { - $parent_def = $definition->info_parent_def; - } else { - $parent_def = $definition->info[$parent_name]; - } - } else { - // processing as if the parent were the "root" node - // unknown info, it won't be used anyway, in the future, - // we may want to enforce one element only (this is - // necessary for HTML Purifier to clean entire documents - $parent_index = $parent_name = $parent_def = null; - } - - // calculate context - if ($is_inline === false) { - // check if conditions make it inline - if (!empty($parent_def) && $parent_def->descendants_are_inline) { - $is_inline = $count - 1; - } - } else { - // check if we're out of inline - if ($count === $is_inline) { - $is_inline = false; - } - } - - //################################################################// - // Determine whether element is explicitly excluded SGML-style - - // determine whether or not element is excluded by checking all - // parent exclusions. The array should not be very large, two - // elements at most. - $excluded = false; - if (!empty($exclude_stack)) { - foreach ($exclude_stack as $lookup) { - if (isset($lookup[$tokens[$i]->name])) { - $excluded = true; - // no need to continue processing - break; - } - } - } - - //################################################################// - // Perform child validation - - if ($excluded) { - // there is an exclusion, remove the entire node - $result = false; - $excludes = array(); // not used, but good to initialize anyway - } else { - // DEFINITION CALL - if ($i === 0) { - // special processing for the first node - $def = $definition->info_parent_def; - } else { - $def = $definition->info[$tokens[$i]->name]; - - } - - if (!empty($def->child)) { - // have DTD child def validate children - $result = $def->child->validateChildren( - $child_tokens, $config, $context); - } else { - // weird, no child definition, get rid of everything - $result = false; - } - - // determine whether or not this element has any exclusions - $excludes = $def->excludes; - } - - // $result is now a bool or array - - //################################################################// - // Process result by interpreting $result - - if ($result === true || $child_tokens === $result) { - // leave the node as is - - // register start token as a parental node start - $stack[] = $i; - - // register exclusions if there are any - if (!empty($excludes)) $exclude_stack[] = $excludes; - - // move cursor to next possible start node - $i++; - - } elseif($result === false) { - // remove entire node - - if ($e) { - if ($excluded) { - $e->send(E_ERROR, 'Strategy_FixNesting: Node excluded'); - } else { - $e->send(E_ERROR, 'Strategy_FixNesting: Node removed'); - } - } - - // calculate length of inner tokens and current tokens - $length = $j - $i + 1; - - // perform removal - array_splice($tokens, $i, $length); - - // update size - $size -= $length; - - // there is no start token to register, - // current node is now the next possible start node - // unless it turns out that we need to do a double-check - - // this is a rought heuristic that covers 100% of HTML's - // cases and 99% of all other cases. A child definition - // that would be tricked by this would be something like: - // ( | a b c) where it's all or nothing. Fortunately, - // our current implementation claims that that case would - // not allow empty, even if it did - if (!$parent_def->child->allow_empty) { - // we need to do a double-check - $i = $parent_index; - array_pop($stack); - } - - // PROJECTED OPTIMIZATION: Process all children elements before - // reprocessing parent node. - - } else { - // replace node with $result - - // calculate length of inner tokens - $length = $j - $i - 1; - - if ($e) { - if (empty($result) && $length) { - $e->send(E_ERROR, 'Strategy_FixNesting: Node contents removed'); - } else { - $e->send(E_WARNING, 'Strategy_FixNesting: Node reorganized'); - } - } - - // perform replacement - array_splice($tokens, $i + 1, $length, $result); - - // update size - $size -= $length; - $size += count($result); - - // register start token as a parental node start - $stack[] = $i; - - // register exclusions if there are any - if (!empty($excludes)) $exclude_stack[] = $excludes; - - // move cursor to next possible start node - $i++; - - } - - //################################################################// - // Scroll to next start node - - // We assume, at this point, that $i is the index of the token - // that is the first possible new start point for a node. - - // Test if the token indeed is a start tag, if not, move forward - // and test again. - $size = count($tokens); - while ($i < $size and !$tokens[$i] instanceof HTMLPurifier_Token_Start) { - if ($tokens[$i] instanceof HTMLPurifier_Token_End) { - // pop a token index off the stack if we ended a node - array_pop($stack); - // pop an exclusion lookup off exclusion stack if - // we ended node and that node had exclusions - if ($i == 0 || $i == $size - 1) { - // use specialized var if it's the super-parent - $s_excludes = $definition->info_parent_def->excludes; - } else { - $s_excludes = $definition->info[$tokens[$i]->name]->excludes; - } - if ($s_excludes) { - array_pop($exclude_stack); - } - } - $i++; - } - - } - - //####################################################################// - // Post-processing - - // remove implicit parent tokens at the beginning and end - array_shift($tokens); - array_pop($tokens); - - // remove context variables - $context->destroy('IsInline'); - $context->destroy('CurrentToken'); - - //####################################################################// - // Return - - return $tokens; - - } - -} - -// vim: et sw=4 sts=4 diff --git a/modules/gallery/lib/HTMLPurifier/HTMLPurifier/Strategy/MakeWellFormed.php b/modules/gallery/lib/HTMLPurifier/HTMLPurifier/Strategy/MakeWellFormed.php deleted file mode 100644 index c81b6b7b..00000000 --- a/modules/gallery/lib/HTMLPurifier/HTMLPurifier/Strategy/MakeWellFormed.php +++ /dev/null @@ -1,457 +0,0 @@ -getHTMLDefinition(); - - // local variables - $generator = new HTMLPurifier_Generator($config, $context); - $escape_invalid_tags = $config->get('Core.EscapeInvalidTags'); - $e = $context->get('ErrorCollector', true); - $t = false; // token index - $i = false; // injector index - $token = false; // the current token - $reprocess = false; // whether or not to reprocess the same token - $stack = array(); - - // member variables - $this->stack =& $stack; - $this->t =& $t; - $this->tokens =& $tokens; - $this->config = $config; - $this->context = $context; - - // context variables - $context->register('CurrentNesting', $stack); - $context->register('InputIndex', $t); - $context->register('InputTokens', $tokens); - $context->register('CurrentToken', $token); - - // -- begin INJECTOR -- - - $this->injectors = array(); - - $injectors = $config->getBatch('AutoFormat'); - $def_injectors = $definition->info_injector; - $custom_injectors = $injectors['Custom']; - unset($injectors['Custom']); // special case - foreach ($injectors as $injector => $b) { - // XXX: Fix with a legitimate lookup table of enabled filters - if (strpos($injector, '.') !== false) continue; - $injector = "HTMLPurifier_Injector_$injector"; - if (!$b) continue; - $this->injectors[] = new $injector; - } - foreach ($def_injectors as $injector) { - // assumed to be objects - $this->injectors[] = $injector; - } - foreach ($custom_injectors as $injector) { - if (is_string($injector)) { - $injector = "HTMLPurifier_Injector_$injector"; - $injector = new $injector; - } - $this->injectors[] = $injector; - } - - // give the injectors references to the definition and context - // variables for performance reasons - foreach ($this->injectors as $ix => $injector) { - $error = $injector->prepare($config, $context); - if (!$error) continue; - array_splice($this->injectors, $ix, 1); // rm the injector - trigger_error("Cannot enable {$injector->name} injector because $error is not allowed", E_USER_WARNING); - } - - // -- end INJECTOR -- - - // a note on punting: - // In order to reduce code duplication, whenever some code needs - // to make HTML changes in order to make things "correct", the - // new HTML gets sent through the purifier, regardless of its - // status. This means that if we add a start token, because it - // was totally necessary, we don't have to update nesting; we just - // punt ($reprocess = true; continue;) and it does that for us. - - // isset is in loop because $tokens size changes during loop exec - for ( - $t = 0; - $t == 0 || isset($tokens[$t - 1]); - // only increment if we don't need to reprocess - $reprocess ? $reprocess = false : $t++ - ) { - - // check for a rewind - if (is_int($i) && $i >= 0) { - // possibility: disable rewinding if the current token has a - // rewind set on it already. This would offer protection from - // infinite loop, but might hinder some advanced rewinding. - $rewind_to = $this->injectors[$i]->getRewind(); - if (is_int($rewind_to) && $rewind_to < $t) { - if ($rewind_to < 0) $rewind_to = 0; - while ($t > $rewind_to) { - $t--; - $prev = $tokens[$t]; - // indicate that other injectors should not process this token, - // but we need to reprocess it - unset($prev->skip[$i]); - $prev->rewind = $i; - if ($prev instanceof HTMLPurifier_Token_Start) array_pop($this->stack); - elseif ($prev instanceof HTMLPurifier_Token_End) $this->stack[] = $prev->start; - } - } - $i = false; - } - - // handle case of document end - if (!isset($tokens[$t])) { - // kill processing if stack is empty - if (empty($this->stack)) break; - - // peek - $top_nesting = array_pop($this->stack); - $this->stack[] = $top_nesting; - - // send error - if ($e && !isset($top_nesting->armor['MakeWellFormed_TagClosedError'])) { - $e->send(E_NOTICE, 'Strategy_MakeWellFormed: Tag closed by document end', $top_nesting); - } - - // append, don't splice, since this is the end - $tokens[] = new HTMLPurifier_Token_End($top_nesting->name); - - // punt! - $reprocess = true; - continue; - } - - $token = $tokens[$t]; - - //echo '
                '; printTokens($tokens, $t); printTokens($this->stack); - - // quick-check: if it's not a tag, no need to process - if (empty($token->is_tag)) { - if ($token instanceof HTMLPurifier_Token_Text) { - foreach ($this->injectors as $i => $injector) { - if (isset($token->skip[$i])) continue; - if ($token->rewind !== null && $token->rewind !== $i) continue; - $injector->handleText($token); - $this->processToken($token, $i); - $reprocess = true; - break; - } - } - // another possibility is a comment - continue; - } - - if (isset($definition->info[$token->name])) { - $type = $definition->info[$token->name]->child->type; - } else { - $type = false; // Type is unknown, treat accordingly - } - - // quick tag checks: anything that's *not* an end tag - $ok = false; - if ($type === 'empty' && $token instanceof HTMLPurifier_Token_Start) { - // claims to be a start tag but is empty - $token = new HTMLPurifier_Token_Empty($token->name, $token->attr); - $ok = true; - } elseif ($type && $type !== 'empty' && $token instanceof HTMLPurifier_Token_Empty) { - // claims to be empty but really is a start tag - $this->swap(new HTMLPurifier_Token_End($token->name)); - $this->insertBefore(new HTMLPurifier_Token_Start($token->name, $token->attr)); - // punt (since we had to modify the input stream in a non-trivial way) - $reprocess = true; - continue; - } elseif ($token instanceof HTMLPurifier_Token_Empty) { - // real empty token - $ok = true; - } elseif ($token instanceof HTMLPurifier_Token_Start) { - // start tag - - // ...unless they also have to close their parent - if (!empty($this->stack)) { - - $parent = array_pop($this->stack); - $this->stack[] = $parent; - - if (isset($definition->info[$parent->name])) { - $elements = $definition->info[$parent->name]->child->getAllowedElements($config); - $autoclose = !isset($elements[$token->name]); - } else { - $autoclose = false; - } - - $carryover = false; - if ($autoclose && $definition->info[$parent->name]->formatting) { - $carryover = true; - } - - if ($autoclose) { - // errors need to be updated - $new_token = new HTMLPurifier_Token_End($parent->name); - $new_token->start = $parent; - if ($carryover) { - $element = clone $parent; - $element->armor['MakeWellFormed_TagClosedError'] = true; - $element->carryover = true; - $this->processToken(array($new_token, $token, $element)); - } else { - $this->insertBefore($new_token); - } - if ($e && !isset($parent->armor['MakeWellFormed_TagClosedError'])) { - if (!$carryover) { - $e->send(E_NOTICE, 'Strategy_MakeWellFormed: Tag auto closed', $parent); - } else { - $e->send(E_NOTICE, 'Strategy_MakeWellFormed: Tag carryover', $parent); - } - } - $reprocess = true; - continue; - } - - } - $ok = true; - } - - if ($ok) { - foreach ($this->injectors as $i => $injector) { - if (isset($token->skip[$i])) continue; - if ($token->rewind !== null && $token->rewind !== $i) continue; - $injector->handleElement($token); - $this->processToken($token, $i); - $reprocess = true; - break; - } - if (!$reprocess) { - // ah, nothing interesting happened; do normal processing - $this->swap($token); - if ($token instanceof HTMLPurifier_Token_Start) { - $this->stack[] = $token; - } elseif ($token instanceof HTMLPurifier_Token_End) { - throw new HTMLPurifier_Exception('Improper handling of end tag in start code; possible error in MakeWellFormed'); - } - } - continue; - } - - // sanity check: we should be dealing with a closing tag - if (!$token instanceof HTMLPurifier_Token_End) { - throw new HTMLPurifier_Exception('Unaccounted for tag token in input stream, bug in HTML Purifier'); - } - - // make sure that we have something open - if (empty($this->stack)) { - if ($escape_invalid_tags) { - if ($e) $e->send(E_WARNING, 'Strategy_MakeWellFormed: Unnecessary end tag to text'); - $this->swap(new HTMLPurifier_Token_Text( - $generator->generateFromToken($token) - )); - } else { - $this->remove(); - if ($e) $e->send(E_WARNING, 'Strategy_MakeWellFormed: Unnecessary end tag removed'); - } - $reprocess = true; - continue; - } - - // first, check for the simplest case: everything closes neatly. - // Eventually, everything passes through here; if there are problems - // we modify the input stream accordingly and then punt, so that - // the tokens get processed again. - $current_parent = array_pop($this->stack); - if ($current_parent->name == $token->name) { - $token->start = $current_parent; - foreach ($this->injectors as $i => $injector) { - if (isset($token->skip[$i])) continue; - if ($token->rewind !== null && $token->rewind !== $i) continue; - $injector->handleEnd($token); - $this->processToken($token, $i); - $this->stack[] = $current_parent; - $reprocess = true; - break; - } - continue; - } - - // okay, so we're trying to close the wrong tag - - // undo the pop previous pop - $this->stack[] = $current_parent; - - // scroll back the entire nest, trying to find our tag. - // (feature could be to specify how far you'd like to go) - $size = count($this->stack); - // -2 because -1 is the last element, but we already checked that - $skipped_tags = false; - for ($j = $size - 2; $j >= 0; $j--) { - if ($this->stack[$j]->name == $token->name) { - $skipped_tags = array_slice($this->stack, $j); - break; - } - } - - // we didn't find the tag, so remove - if ($skipped_tags === false) { - if ($escape_invalid_tags) { - $this->swap(new HTMLPurifier_Token_Text( - $generator->generateFromToken($token) - )); - if ($e) $e->send(E_WARNING, 'Strategy_MakeWellFormed: Stray end tag to text'); - } else { - $this->remove(); - if ($e) $e->send(E_WARNING, 'Strategy_MakeWellFormed: Stray end tag removed'); - } - $reprocess = true; - continue; - } - - // do errors, in REVERSE $j order: a,b,c with - $c = count($skipped_tags); - if ($e) { - for ($j = $c - 1; $j > 0; $j--) { - // notice we exclude $j == 0, i.e. the current ending tag, from - // the errors... - if (!isset($skipped_tags[$j]->armor['MakeWellFormed_TagClosedError'])) { - $e->send(E_NOTICE, 'Strategy_MakeWellFormed: Tag closed by element end', $skipped_tags[$j]); - } - } - } - - // insert tags, in FORWARD $j order: c,b,a with - $replace = array($token); - for ($j = 1; $j < $c; $j++) { - // ...as well as from the insertions - $new_token = new HTMLPurifier_Token_End($skipped_tags[$j]->name); - $new_token->start = $skipped_tags[$j]; - array_unshift($replace, $new_token); - if (isset($definition->info[$new_token->name]) && $definition->info[$new_token->name]->formatting) { - $element = clone $skipped_tags[$j]; - $element->carryover = true; - $element->armor['MakeWellFormed_TagClosedError'] = true; - $replace[] = $element; - } - } - $this->processToken($replace); - $reprocess = true; - continue; - } - - $context->destroy('CurrentNesting'); - $context->destroy('InputTokens'); - $context->destroy('InputIndex'); - $context->destroy('CurrentToken'); - - unset($this->injectors, $this->stack, $this->tokens, $this->t); - return $tokens; - } - - /** - * Processes arbitrary token values for complicated substitution patterns. - * In general: - * - * If $token is an array, it is a list of tokens to substitute for the - * current token. These tokens then get individually processed. If there - * is a leading integer in the list, that integer determines how many - * tokens from the stream should be removed. - * - * If $token is a regular token, it is swapped with the current token. - * - * If $token is false, the current token is deleted. - * - * If $token is an integer, that number of tokens (with the first token - * being the current one) will be deleted. - * - * @param $token Token substitution value - * @param $injector Injector that performed the substitution; default is if - * this is not an injector related operation. - */ - protected function processToken($token, $injector = -1) { - - // normalize forms of token - if (is_object($token)) $token = array(1, $token); - if (is_int($token)) $token = array($token); - if ($token === false) $token = array(1); - if (!is_array($token)) throw new HTMLPurifier_Exception('Invalid token type from injector'); - if (!is_int($token[0])) array_unshift($token, 1); - if ($token[0] === 0) throw new HTMLPurifier_Exception('Deleting zero tokens is not valid'); - - // $token is now an array with the following form: - // array(number nodes to delete, new node 1, new node 2, ...) - - $delete = array_shift($token); - $old = array_splice($this->tokens, $this->t, $delete, $token); - - if ($injector > -1) { - // determine appropriate skips - $oldskip = isset($old[0]) ? $old[0]->skip : array(); - foreach ($token as $object) { - $object->skip = $oldskip; - $object->skip[$injector] = true; - } - } - - } - - /** - * Inserts a token before the current token. Cursor now points to this token - */ - private function insertBefore($token) { - array_splice($this->tokens, $this->t, 0, array($token)); - } - - /** - * Removes current token. Cursor now points to new token occupying previously - * occupied space. - */ - private function remove() { - array_splice($this->tokens, $this->t, 1); - } - - /** - * Swap current token with new token. Cursor points to new token (no change). - */ - private function swap($token) { - $this->tokens[$this->t] = $token; - } - -} - -// vim: et sw=4 sts=4 diff --git a/modules/gallery/lib/HTMLPurifier/HTMLPurifier/Strategy/RemoveForeignElements.php b/modules/gallery/lib/HTMLPurifier/HTMLPurifier/Strategy/RemoveForeignElements.php deleted file mode 100644 index 9792a0f5..00000000 --- a/modules/gallery/lib/HTMLPurifier/HTMLPurifier/Strategy/RemoveForeignElements.php +++ /dev/null @@ -1,171 +0,0 @@ -getHTMLDefinition(); - $generator = new HTMLPurifier_Generator($config, $context); - $result = array(); - - $escape_invalid_tags = $config->get('Core.EscapeInvalidTags'); - $remove_invalid_img = $config->get('Core.RemoveInvalidImg'); - - // currently only used to determine if comments should be kept - $trusted = $config->get('HTML.Trusted'); - - $remove_script_contents = $config->get('Core.RemoveScriptContents'); - $hidden_elements = $config->get('Core.HiddenElements'); - - // remove script contents compatibility - if ($remove_script_contents === true) { - $hidden_elements['script'] = true; - } elseif ($remove_script_contents === false && isset($hidden_elements['script'])) { - unset($hidden_elements['script']); - } - - $attr_validator = new HTMLPurifier_AttrValidator(); - - // removes tokens until it reaches a closing tag with its value - $remove_until = false; - - // converts comments into text tokens when this is equal to a tag name - $textify_comments = false; - - $token = false; - $context->register('CurrentToken', $token); - - $e = false; - if ($config->get('Core.CollectErrors')) { - $e =& $context->get('ErrorCollector'); - } - - foreach($tokens as $token) { - if ($remove_until) { - if (empty($token->is_tag) || $token->name !== $remove_until) { - continue; - } - } - if (!empty( $token->is_tag )) { - // DEFINITION CALL - - // before any processing, try to transform the element - if ( - isset($definition->info_tag_transform[$token->name]) - ) { - $original_name = $token->name; - // there is a transformation for this tag - // DEFINITION CALL - $token = $definition-> - info_tag_transform[$token->name]-> - transform($token, $config, $context); - if ($e) $e->send(E_NOTICE, 'Strategy_RemoveForeignElements: Tag transform', $original_name); - } - - if (isset($definition->info[$token->name])) { - - // mostly everything's good, but - // we need to make sure required attributes are in order - if ( - ($token instanceof HTMLPurifier_Token_Start || $token instanceof HTMLPurifier_Token_Empty) && - $definition->info[$token->name]->required_attr && - ($token->name != 'img' || $remove_invalid_img) // ensure config option still works - ) { - $attr_validator->validateToken($token, $config, $context); - $ok = true; - foreach ($definition->info[$token->name]->required_attr as $name) { - if (!isset($token->attr[$name])) { - $ok = false; - break; - } - } - if (!$ok) { - if ($e) $e->send(E_ERROR, 'Strategy_RemoveForeignElements: Missing required attribute', $name); - continue; - } - $token->armor['ValidateAttributes'] = true; - } - - if (isset($hidden_elements[$token->name]) && $token instanceof HTMLPurifier_Token_Start) { - $textify_comments = $token->name; - } elseif ($token->name === $textify_comments && $token instanceof HTMLPurifier_Token_End) { - $textify_comments = false; - } - - } elseif ($escape_invalid_tags) { - // invalid tag, generate HTML representation and insert in - if ($e) $e->send(E_WARNING, 'Strategy_RemoveForeignElements: Foreign element to text'); - $token = new HTMLPurifier_Token_Text( - $generator->generateFromToken($token) - ); - } else { - // check if we need to destroy all of the tag's children - // CAN BE GENERICIZED - if (isset($hidden_elements[$token->name])) { - if ($token instanceof HTMLPurifier_Token_Start) { - $remove_until = $token->name; - } elseif ($token instanceof HTMLPurifier_Token_Empty) { - // do nothing: we're still looking - } else { - $remove_until = false; - } - if ($e) $e->send(E_ERROR, 'Strategy_RemoveForeignElements: Foreign meta element removed'); - } else { - if ($e) $e->send(E_ERROR, 'Strategy_RemoveForeignElements: Foreign element removed'); - } - continue; - } - } elseif ($token instanceof HTMLPurifier_Token_Comment) { - // textify comments in script tags when they are allowed - if ($textify_comments !== false) { - $data = $token->data; - $token = new HTMLPurifier_Token_Text($data); - } elseif ($trusted) { - // keep, but perform comment cleaning - if ($e) { - // perform check whether or not there's a trailing hyphen - if (substr($token->data, -1) == '-') { - $e->send(E_NOTICE, 'Strategy_RemoveForeignElements: Trailing hyphen in comment removed'); - } - } - $token->data = rtrim($token->data, '-'); - $found_double_hyphen = false; - while (strpos($token->data, '--') !== false) { - if ($e && !$found_double_hyphen) { - $e->send(E_NOTICE, 'Strategy_RemoveForeignElements: Hyphens in comment collapsed'); - } - $found_double_hyphen = true; // prevent double-erroring - $token->data = str_replace('--', '-', $token->data); - } - } else { - // strip comments - if ($e) $e->send(E_NOTICE, 'Strategy_RemoveForeignElements: Comment removed'); - continue; - } - } elseif ($token instanceof HTMLPurifier_Token_Text) { - } else { - continue; - } - $result[] = $token; - } - if ($remove_until && $e) { - // we removed tokens until the end, throw error - $e->send(E_ERROR, 'Strategy_RemoveForeignElements: Token removed to end', $remove_until); - } - - $context->destroy('CurrentToken'); - - return $result; - } - -} - -// vim: et sw=4 sts=4 diff --git a/modules/gallery/lib/HTMLPurifier/HTMLPurifier/Strategy/ValidateAttributes.php b/modules/gallery/lib/HTMLPurifier/HTMLPurifier/Strategy/ValidateAttributes.php deleted file mode 100644 index d5e03b7b..00000000 --- a/modules/gallery/lib/HTMLPurifier/HTMLPurifier/Strategy/ValidateAttributes.php +++ /dev/null @@ -1,39 +0,0 @@ -register('CurrentToken', $token); - - foreach ($tokens as $key => $token) { - - // only process tokens that have attributes, - // namely start and empty tags - if (!$token instanceof HTMLPurifier_Token_Start && !$token instanceof HTMLPurifier_Token_Empty) continue; - - // skip tokens that are armored - if (!empty($token->armor['ValidateAttributes'])) continue; - - // note that we have no facilities here for removing tokens - $validator->validateToken($token, $config, $context); - - $tokens[$key] = $token; // for PHP 4 - } - $context->destroy('CurrentToken'); - - return $tokens; - } - -} - -// vim: et sw=4 sts=4 diff --git a/modules/gallery/lib/HTMLPurifier/HTMLPurifier/StringHash.php b/modules/gallery/lib/HTMLPurifier/HTMLPurifier/StringHash.php deleted file mode 100644 index 2161685e..00000000 --- a/modules/gallery/lib/HTMLPurifier/HTMLPurifier/StringHash.php +++ /dev/null @@ -1,39 +0,0 @@ -accessed[$index] = true; - return parent::offsetGet($index); - } - - /** - * Returns a lookup array of all array indexes that have been accessed. - * @return Array in form array($index => true). - */ - public function getAccessed() { - return $this->accessed; - } - - /** - * Resets the access array. - */ - public function resetAccessed() { - $this->accessed = array(); - } -} - -// vim: et sw=4 sts=4 diff --git a/modules/gallery/lib/HTMLPurifier/HTMLPurifier/StringHashParser.php b/modules/gallery/lib/HTMLPurifier/HTMLPurifier/StringHashParser.php deleted file mode 100644 index 03deefce..00000000 --- a/modules/gallery/lib/HTMLPurifier/HTMLPurifier/StringHashParser.php +++ /dev/null @@ -1,110 +0,0 @@ - 'DefaultKeyValue', - * 'KEY' => 'Value', - * 'KEY2' => 'Value2', - * 'MULTILINE-KEY' => "Multiline\nvalue.\n", - * ) - * - * We use this as an easy to use file-format for configuration schema - * files, but the class itself is usage agnostic. - * - * You can use ---- to forcibly terminate parsing of a single string-hash; - * this marker is used in multi string-hashes to delimit boundaries. - */ -class HTMLPurifier_StringHashParser -{ - - public $default = 'ID'; - - /** - * Parses a file that contains a single string-hash. - */ - public function parseFile($file) { - if (!file_exists($file)) return false; - $fh = fopen($file, 'r'); - if (!$fh) return false; - $ret = $this->parseHandle($fh); - fclose($fh); - return $ret; - } - - /** - * Parses a file that contains multiple string-hashes delimited by '----' - */ - public function parseMultiFile($file) { - if (!file_exists($file)) return false; - $ret = array(); - $fh = fopen($file, 'r'); - if (!$fh) return false; - while (!feof($fh)) { - $ret[] = $this->parseHandle($fh); - } - fclose($fh); - return $ret; - } - - /** - * Internal parser that acepts a file handle. - * @note While it's possible to simulate in-memory parsing by using - * custom stream wrappers, if such a use-case arises we should - * factor out the file handle into its own class. - * @param $fh File handle with pointer at start of valid string-hash - * block. - */ - protected function parseHandle($fh) { - $state = false; - $single = false; - $ret = array(); - do { - $line = fgets($fh); - if ($line === false) break; - $line = rtrim($line, "\n\r"); - if (!$state && $line === '') continue; - if ($line === '----') break; - if (strncmp('--#', $line, 3) === 0) { - // Comment - continue; - } elseif (strncmp('--', $line, 2) === 0) { - // Multiline declaration - $state = trim($line, '- '); - if (!isset($ret[$state])) $ret[$state] = ''; - continue; - } elseif (!$state) { - $single = true; - if (strpos($line, ':') !== false) { - // Single-line declaration - list($state, $line) = explode(':', $line, 2); - $line = trim($line); - } else { - // Use default declaration - $state = $this->default; - } - } - if ($single) { - $ret[$state] = $line; - $single = false; - $state = false; - } else { - $ret[$state] .= "$line\n"; - } - } while (!feof($fh)); - return $ret; - } - -} - -// vim: et sw=4 sts=4 diff --git a/modules/gallery/lib/HTMLPurifier/HTMLPurifier/TagTransform.php b/modules/gallery/lib/HTMLPurifier/HTMLPurifier/TagTransform.php deleted file mode 100644 index a8a1f45d..00000000 --- a/modules/gallery/lib/HTMLPurifier/HTMLPurifier/TagTransform.php +++ /dev/null @@ -1,36 +0,0 @@ - 'xx-small', - '1' => 'xx-small', - '2' => 'small', - '3' => 'medium', - '4' => 'large', - '5' => 'x-large', - '6' => 'xx-large', - '7' => '300%', - '-1' => 'smaller', - '-2' => '60%', - '+1' => 'larger', - '+2' => '150%', - '+3' => '200%', - '+4' => '300%' - ); - - public function transform($tag, $config, $context) { - - if ($tag instanceof HTMLPurifier_Token_End) { - $new_tag = clone $tag; - $new_tag->name = $this->transform_to; - return $new_tag; - } - - $attr = $tag->attr; - $prepend_style = ''; - - // handle color transform - if (isset($attr['color'])) { - $prepend_style .= 'color:' . $attr['color'] . ';'; - unset($attr['color']); - } - - // handle face transform - if (isset($attr['face'])) { - $prepend_style .= 'font-family:' . $attr['face'] . ';'; - unset($attr['face']); - } - - // handle size transform - if (isset($attr['size'])) { - // normalize large numbers - if ($attr['size']{0} == '+' || $attr['size']{0} == '-') { - $size = (int) $attr['size']; - if ($size < -2) $attr['size'] = '-2'; - if ($size > 4) $attr['size'] = '+4'; - } else { - $size = (int) $attr['size']; - if ($size > 7) $attr['size'] = '7'; - } - if (isset($this->_size_lookup[$attr['size']])) { - $prepend_style .= 'font-size:' . - $this->_size_lookup[$attr['size']] . ';'; - } - unset($attr['size']); - } - - if ($prepend_style) { - $attr['style'] = isset($attr['style']) ? - $prepend_style . $attr['style'] : - $prepend_style; - } - - $new_tag = clone $tag; - $new_tag->name = $this->transform_to; - $new_tag->attr = $attr; - - return $new_tag; - - } -} - -// vim: et sw=4 sts=4 diff --git a/modules/gallery/lib/HTMLPurifier/HTMLPurifier/TagTransform/Simple.php b/modules/gallery/lib/HTMLPurifier/HTMLPurifier/TagTransform/Simple.php deleted file mode 100644 index ced91503..00000000 --- a/modules/gallery/lib/HTMLPurifier/HTMLPurifier/TagTransform/Simple.php +++ /dev/null @@ -1,35 +0,0 @@ -transform_to = $transform_to; - $this->style = $style; - } - - public function transform($tag, $config, $context) { - $new_tag = clone $tag; - $new_tag->name = $this->transform_to; - if (!is_null($this->style) && - ($new_tag instanceof HTMLPurifier_Token_Start || $new_tag instanceof HTMLPurifier_Token_Empty) - ) { - $this->prependCSS($new_tag->attr, $this->style); - } - return $new_tag; - } - -} - -// vim: et sw=4 sts=4 diff --git a/modules/gallery/lib/HTMLPurifier/HTMLPurifier/Token.php b/modules/gallery/lib/HTMLPurifier/HTMLPurifier/Token.php deleted file mode 100644 index 22bebcf7..00000000 --- a/modules/gallery/lib/HTMLPurifier/HTMLPurifier/Token.php +++ /dev/null @@ -1,57 +0,0 @@ -line = $l; - $this->col = $c; - } - - /** - * Convenience function for DirectLex settings line/col position. - */ - public function rawPosition($l, $c) { - if ($c === -1) $l++; - $this->line = $l; - $this->col = $c; - } - -} - -// vim: et sw=4 sts=4 diff --git a/modules/gallery/lib/HTMLPurifier/HTMLPurifier/Token/Comment.php b/modules/gallery/lib/HTMLPurifier/HTMLPurifier/Token/Comment.php deleted file mode 100644 index 592f2eea..00000000 --- a/modules/gallery/lib/HTMLPurifier/HTMLPurifier/Token/Comment.php +++ /dev/null @@ -1,22 +0,0 @@ -data = $data; - $this->line = $line; - $this->col = $col; - } -} - -// vim: et sw=4 sts=4 diff --git a/modules/gallery/lib/HTMLPurifier/HTMLPurifier/Token/Empty.php b/modules/gallery/lib/HTMLPurifier/HTMLPurifier/Token/Empty.php deleted file mode 100644 index 842c54da..00000000 --- a/modules/gallery/lib/HTMLPurifier/HTMLPurifier/Token/Empty.php +++ /dev/null @@ -1,11 +0,0 @@ -!empty($obj->is_tag) - * without having to use a function call is_a(). - */ - public $is_tag = true; - - /** - * The lower-case name of the tag, like 'a', 'b' or 'blockquote'. - * - * @note Strictly speaking, XML tags are case sensitive, so we shouldn't - * be lower-casing them, but these tokens cater to HTML tags, which are - * insensitive. - */ - public $name; - - /** - * Associative array of the tag's attributes. - */ - public $attr = array(); - - /** - * Non-overloaded constructor, which lower-cases passed tag name. - * - * @param $name String name. - * @param $attr Associative array of attributes. - */ - public function __construct($name, $attr = array(), $line = null, $col = null) { - $this->name = ctype_lower($name) ? $name : strtolower($name); - foreach ($attr as $key => $value) { - // normalization only necessary when key is not lowercase - if (!ctype_lower($key)) { - $new_key = strtolower($key); - if (!isset($attr[$new_key])) { - $attr[$new_key] = $attr[$key]; - } - if ($new_key !== $key) { - unset($attr[$key]); - } - } - } - $this->attr = $attr; - $this->line = $line; - $this->col = $col; - } -} - -// vim: et sw=4 sts=4 diff --git a/modules/gallery/lib/HTMLPurifier/HTMLPurifier/Token/Text.php b/modules/gallery/lib/HTMLPurifier/HTMLPurifier/Token/Text.php deleted file mode 100644 index 0d82f75a..00000000 --- a/modules/gallery/lib/HTMLPurifier/HTMLPurifier/Token/Text.php +++ /dev/null @@ -1,33 +0,0 @@ -data = $data; - $this->is_whitespace = ctype_space($data); - $this->line = $line; - $this->col = $col; - } - -} - -// vim: et sw=4 sts=4 diff --git a/modules/gallery/lib/HTMLPurifier/HTMLPurifier/TokenFactory.php b/modules/gallery/lib/HTMLPurifier/HTMLPurifier/TokenFactory.php deleted file mode 100644 index 16c969cf..00000000 --- a/modules/gallery/lib/HTMLPurifier/HTMLPurifier/TokenFactory.php +++ /dev/null @@ -1,94 +0,0 @@ -p_start = new HTMLPurifier_Token_Start('', array()); - $this->p_end = new HTMLPurifier_Token_End(''); - $this->p_empty = new HTMLPurifier_Token_Empty('', array()); - $this->p_text = new HTMLPurifier_Token_Text(''); - $this->p_comment= new HTMLPurifier_Token_Comment(''); - } - - /** - * Creates a HTMLPurifier_Token_Start. - * @param $name Tag name - * @param $attr Associative array of attributes - * @return Generated HTMLPurifier_Token_Start - */ - public function createStart($name, $attr = array()) { - $p = clone $this->p_start; - $p->__construct($name, $attr); - return $p; - } - - /** - * Creates a HTMLPurifier_Token_End. - * @param $name Tag name - * @return Generated HTMLPurifier_Token_End - */ - public function createEnd($name) { - $p = clone $this->p_end; - $p->__construct($name); - return $p; - } - - /** - * Creates a HTMLPurifier_Token_Empty. - * @param $name Tag name - * @param $attr Associative array of attributes - * @return Generated HTMLPurifier_Token_Empty - */ - public function createEmpty($name, $attr = array()) { - $p = clone $this->p_empty; - $p->__construct($name, $attr); - return $p; - } - - /** - * Creates a HTMLPurifier_Token_Text. - * @param $data Data of text token - * @return Generated HTMLPurifier_Token_Text - */ - public function createText($data) { - $p = clone $this->p_text; - $p->__construct($data); - return $p; - } - - /** - * Creates a HTMLPurifier_Token_Comment. - * @param $data Data of comment token - * @return Generated HTMLPurifier_Token_Comment - */ - public function createComment($data) { - $p = clone $this->p_comment; - $p->__construct($data); - return $p; - } - -} - -// vim: et sw=4 sts=4 diff --git a/modules/gallery/lib/HTMLPurifier/HTMLPurifier/URI.php b/modules/gallery/lib/HTMLPurifier/HTMLPurifier/URI.php deleted file mode 100644 index ac983b86..00000000 --- a/modules/gallery/lib/HTMLPurifier/HTMLPurifier/URI.php +++ /dev/null @@ -1,173 +0,0 @@ -scheme = is_null($scheme) || ctype_lower($scheme) ? $scheme : strtolower($scheme); - $this->userinfo = $userinfo; - $this->host = $host; - $this->port = is_null($port) ? $port : (int) $port; - $this->path = $path; - $this->query = $query; - $this->fragment = $fragment; - } - - /** - * Retrieves a scheme object corresponding to the URI's scheme/default - * @param $config Instance of HTMLPurifier_Config - * @param $context Instance of HTMLPurifier_Context - * @return Scheme object appropriate for validating this URI - */ - public function getSchemeObj($config, $context) { - $registry = HTMLPurifier_URISchemeRegistry::instance(); - if ($this->scheme !== null) { - $scheme_obj = $registry->getScheme($this->scheme, $config, $context); - if (!$scheme_obj) return false; // invalid scheme, clean it out - } else { - // no scheme: retrieve the default one - $def = $config->getDefinition('URI'); - $scheme_obj = $registry->getScheme($def->defaultScheme, $config, $context); - if (!$scheme_obj) { - // something funky happened to the default scheme object - trigger_error( - 'Default scheme object "' . $def->defaultScheme . '" was not readable', - E_USER_WARNING - ); - return false; - } - } - return $scheme_obj; - } - - /** - * Generic validation method applicable for all schemes. May modify - * this URI in order to get it into a compliant form. - * @param $config Instance of HTMLPurifier_Config - * @param $context Instance of HTMLPurifier_Context - * @return True if validation/filtering succeeds, false if failure - */ - public function validate($config, $context) { - - // ABNF definitions from RFC 3986 - $chars_sub_delims = '!$&\'()*+,;='; - $chars_gen_delims = ':/?#[]@'; - $chars_pchar = $chars_sub_delims . ':@'; - - // validate scheme (MUST BE FIRST!) - if (!is_null($this->scheme) && is_null($this->host)) { - $def = $config->getDefinition('URI'); - if ($def->defaultScheme === $this->scheme) { - $this->scheme = null; - } - } - - // validate host - if (!is_null($this->host)) { - $host_def = new HTMLPurifier_AttrDef_URI_Host(); - $this->host = $host_def->validate($this->host, $config, $context); - if ($this->host === false) $this->host = null; - } - - // validate username - if (!is_null($this->userinfo)) { - $encoder = new HTMLPurifier_PercentEncoder($chars_sub_delims . ':'); - $this->userinfo = $encoder->encode($this->userinfo); - } - - // validate port - if (!is_null($this->port)) { - if ($this->port < 1 || $this->port > 65535) $this->port = null; - } - - // validate path - $path_parts = array(); - $segments_encoder = new HTMLPurifier_PercentEncoder($chars_pchar . '/'); - if (!is_null($this->host)) { - // path-abempty (hier and relative) - $this->path = $segments_encoder->encode($this->path); - } elseif ($this->path !== '' && $this->path[0] === '/') { - // path-absolute (hier and relative) - if (strlen($this->path) >= 2 && $this->path[1] === '/') { - // This shouldn't ever happen! - $this->path = ''; - } else { - $this->path = $segments_encoder->encode($this->path); - } - } elseif (!is_null($this->scheme) && $this->path !== '') { - // path-rootless (hier) - // Short circuit evaluation means we don't need to check nz - $this->path = $segments_encoder->encode($this->path); - } elseif (is_null($this->scheme) && $this->path !== '') { - // path-noscheme (relative) - // (once again, not checking nz) - $segment_nc_encoder = new HTMLPurifier_PercentEncoder($chars_sub_delims . '@'); - $c = strpos($this->path, '/'); - if ($c !== false) { - $this->path = - $segment_nc_encoder->encode(substr($this->path, 0, $c)) . - $segments_encoder->encode(substr($this->path, $c)); - } else { - $this->path = $segment_nc_encoder->encode($this->path); - } - } else { - // path-empty (hier and relative) - $this->path = ''; // just to be safe - } - - // qf = query and fragment - $qf_encoder = new HTMLPurifier_PercentEncoder($chars_pchar . '/?'); - - if (!is_null($this->query)) { - $this->query = $qf_encoder->encode($this->query); - } - - if (!is_null($this->fragment)) { - $this->fragment = $qf_encoder->encode($this->fragment); - } - - return true; - - } - - /** - * Convert URI back to string - * @return String URI appropriate for output - */ - public function toString() { - // reconstruct authority - $authority = null; - if (!is_null($this->host)) { - $authority = ''; - if(!is_null($this->userinfo)) $authority .= $this->userinfo . '@'; - $authority .= $this->host; - if(!is_null($this->port)) $authority .= ':' . $this->port; - } - - // reconstruct the result - $result = ''; - if (!is_null($this->scheme)) $result .= $this->scheme . ':'; - if (!is_null($authority)) $result .= '//' . $authority; - $result .= $this->path; - if (!is_null($this->query)) $result .= '?' . $this->query; - if (!is_null($this->fragment)) $result .= '#' . $this->fragment; - - return $result; - } - -} - -// vim: et sw=4 sts=4 diff --git a/modules/gallery/lib/HTMLPurifier/HTMLPurifier/URIDefinition.php b/modules/gallery/lib/HTMLPurifier/HTMLPurifier/URIDefinition.php deleted file mode 100644 index 86ac169c..00000000 --- a/modules/gallery/lib/HTMLPurifier/HTMLPurifier/URIDefinition.php +++ /dev/null @@ -1,93 +0,0 @@ -registerFilter(new HTMLPurifier_URIFilter_DisableExternal()); - $this->registerFilter(new HTMLPurifier_URIFilter_DisableExternalResources()); - $this->registerFilter(new HTMLPurifier_URIFilter_HostBlacklist()); - $this->registerFilter(new HTMLPurifier_URIFilter_MakeAbsolute()); - $this->registerFilter(new HTMLPurifier_URIFilter_Munge()); - } - - public function registerFilter($filter) { - $this->registeredFilters[$filter->name] = $filter; - } - - public function addFilter($filter, $config) { - $r = $filter->prepare($config); - if ($r === false) return; // null is ok, for backwards compat - if ($filter->post) { - $this->postFilters[$filter->name] = $filter; - } else { - $this->filters[$filter->name] = $filter; - } - } - - protected function doSetup($config) { - $this->setupMemberVariables($config); - $this->setupFilters($config); - } - - protected function setupFilters($config) { - foreach ($this->registeredFilters as $name => $filter) { - $conf = $config->get('URI.' . $name); - if ($conf !== false && $conf !== null) { - $this->addFilter($filter, $config); - } - } - unset($this->registeredFilters); - } - - protected function setupMemberVariables($config) { - $this->host = $config->get('URI.Host'); - $base_uri = $config->get('URI.Base'); - if (!is_null($base_uri)) { - $parser = new HTMLPurifier_URIParser(); - $this->base = $parser->parse($base_uri); - $this->defaultScheme = $this->base->scheme; - if (is_null($this->host)) $this->host = $this->base->host; - } - if (is_null($this->defaultScheme)) $this->defaultScheme = $config->get('URI.DefaultScheme'); - } - - public function filter(&$uri, $config, $context) { - foreach ($this->filters as $name => $f) { - $result = $f->filter($uri, $config, $context); - if (!$result) return false; - } - return true; - } - - public function postFilter(&$uri, $config, $context) { - foreach ($this->postFilters as $name => $f) { - $result = $f->filter($uri, $config, $context); - if (!$result) return false; - } - return true; - } - -} - -// vim: et sw=4 sts=4 diff --git a/modules/gallery/lib/HTMLPurifier/HTMLPurifier/URIFilter.php b/modules/gallery/lib/HTMLPurifier/HTMLPurifier/URIFilter.php deleted file mode 100644 index 8c73051e..00000000 --- a/modules/gallery/lib/HTMLPurifier/HTMLPurifier/URIFilter.php +++ /dev/null @@ -1,45 +0,0 @@ -getDefinition('URI')->host; - if ($our_host !== null) $this->ourHostParts = array_reverse(explode('.', $our_host)); - } - public function filter(&$uri, $config, $context) { - if (is_null($uri->host)) return true; - if ($this->ourHostParts === false) return false; - $host_parts = array_reverse(explode('.', $uri->host)); - foreach ($this->ourHostParts as $i => $x) { - if (!isset($host_parts[$i])) return false; - if ($host_parts[$i] != $this->ourHostParts[$i]) return false; - } - return true; - } -} - -// vim: et sw=4 sts=4 diff --git a/modules/gallery/lib/HTMLPurifier/HTMLPurifier/URIFilter/DisableExternalResources.php b/modules/gallery/lib/HTMLPurifier/HTMLPurifier/URIFilter/DisableExternalResources.php deleted file mode 100644 index b10370c9..00000000 --- a/modules/gallery/lib/HTMLPurifier/HTMLPurifier/URIFilter/DisableExternalResources.php +++ /dev/null @@ -1,12 +0,0 @@ -get('EmbeddedURI', true)) return true; - return parent::filter($uri, $config, $context); - } -} - -// vim: et sw=4 sts=4 diff --git a/modules/gallery/lib/HTMLPurifier/HTMLPurifier/URIFilter/HostBlacklist.php b/modules/gallery/lib/HTMLPurifier/HTMLPurifier/URIFilter/HostBlacklist.php deleted file mode 100644 index 11463f8f..00000000 --- a/modules/gallery/lib/HTMLPurifier/HTMLPurifier/URIFilter/HostBlacklist.php +++ /dev/null @@ -1,21 +0,0 @@ -blacklist = $config->get('URI.HostBlacklist'); - return true; - } - public function filter(&$uri, $config, $context) { - foreach($this->blacklist as $blacklisted_host_fragment) { - if (strpos($uri->host, $blacklisted_host_fragment) !== false) { - return false; - } - } - return true; - } -} - -// vim: et sw=4 sts=4 diff --git a/modules/gallery/lib/HTMLPurifier/HTMLPurifier/URIFilter/MakeAbsolute.php b/modules/gallery/lib/HTMLPurifier/HTMLPurifier/URIFilter/MakeAbsolute.php deleted file mode 100644 index 5f3c5ad3..00000000 --- a/modules/gallery/lib/HTMLPurifier/HTMLPurifier/URIFilter/MakeAbsolute.php +++ /dev/null @@ -1,114 +0,0 @@ -getDefinition('URI'); - $this->base = $def->base; - if (is_null($this->base)) { - trigger_error('URI.MakeAbsolute is being ignored due to lack of value for URI.Base configuration', E_USER_WARNING); - return false; - } - $this->base->fragment = null; // fragment is invalid for base URI - $stack = explode('/', $this->base->path); - array_pop($stack); // discard last segment - $stack = $this->_collapseStack($stack); // do pre-parsing - $this->basePathStack = $stack; - return true; - } - public function filter(&$uri, $config, $context) { - if (is_null($this->base)) return true; // abort early - if ( - $uri->path === '' && is_null($uri->scheme) && - is_null($uri->host) && is_null($uri->query) && is_null($uri->fragment) - ) { - // reference to current document - $uri = clone $this->base; - return true; - } - if (!is_null($uri->scheme)) { - // absolute URI already: don't change - if (!is_null($uri->host)) return true; - $scheme_obj = $uri->getSchemeObj($config, $context); - if (!$scheme_obj) { - // scheme not recognized - return false; - } - if (!$scheme_obj->hierarchical) { - // non-hierarchal URI with explicit scheme, don't change - return true; - } - // special case: had a scheme but always is hierarchical and had no authority - } - if (!is_null($uri->host)) { - // network path, don't bother - return true; - } - if ($uri->path === '') { - $uri->path = $this->base->path; - } elseif ($uri->path[0] !== '/') { - // relative path, needs more complicated processing - $stack = explode('/', $uri->path); - $new_stack = array_merge($this->basePathStack, $stack); - if ($new_stack[0] !== '' && !is_null($this->base->host)) { - array_unshift($new_stack, ''); - } - $new_stack = $this->_collapseStack($new_stack); - $uri->path = implode('/', $new_stack); - } else { - // absolute path, but still we should collapse - $uri->path = implode('/', $this->_collapseStack(explode('/', $uri->path))); - } - // re-combine - $uri->scheme = $this->base->scheme; - if (is_null($uri->userinfo)) $uri->userinfo = $this->base->userinfo; - if (is_null($uri->host)) $uri->host = $this->base->host; - if (is_null($uri->port)) $uri->port = $this->base->port; - return true; - } - - /** - * Resolve dots and double-dots in a path stack - */ - private function _collapseStack($stack) { - $result = array(); - $is_folder = false; - for ($i = 0; isset($stack[$i]); $i++) { - $is_folder = false; - // absorb an internally duplicated slash - if ($stack[$i] == '' && $i && isset($stack[$i+1])) continue; - if ($stack[$i] == '..') { - if (!empty($result)) { - $segment = array_pop($result); - if ($segment === '' && empty($result)) { - // error case: attempted to back out too far: - // restore the leading slash - $result[] = ''; - } elseif ($segment === '..') { - $result[] = '..'; // cannot remove .. with .. - } - } else { - // relative path, preserve the double-dots - $result[] = '..'; - } - $is_folder = true; - continue; - } - if ($stack[$i] == '.') { - // silently absorb - $is_folder = true; - continue; - } - $result[] = $stack[$i]; - } - if ($is_folder) $result[] = ''; - return $result; - } -} - -// vim: et sw=4 sts=4 diff --git a/modules/gallery/lib/HTMLPurifier/HTMLPurifier/URIFilter/Munge.php b/modules/gallery/lib/HTMLPurifier/HTMLPurifier/URIFilter/Munge.php deleted file mode 100644 index 16969bed..00000000 --- a/modules/gallery/lib/HTMLPurifier/HTMLPurifier/URIFilter/Munge.php +++ /dev/null @@ -1,58 +0,0 @@ -target = $config->get('URI.' . $this->name); - $this->parser = new HTMLPurifier_URIParser(); - $this->doEmbed = $config->get('URI.MungeResources'); - $this->secretKey = $config->get('URI.MungeSecretKey'); - return true; - } - public function filter(&$uri, $config, $context) { - if ($context->get('EmbeddedURI', true) && !$this->doEmbed) return true; - - $scheme_obj = $uri->getSchemeObj($config, $context); - if (!$scheme_obj) return true; // ignore unknown schemes, maybe another postfilter did it - if (is_null($uri->host) || empty($scheme_obj->browsable)) { - return true; - } - // don't redirect if target host is our host - if ($uri->host === $config->getDefinition('URI')->host) { - return true; - } - - $this->makeReplace($uri, $config, $context); - $this->replace = array_map('rawurlencode', $this->replace); - - $new_uri = strtr($this->target, $this->replace); - $new_uri = $this->parser->parse($new_uri); - // don't redirect if the target host is the same as the - // starting host - if ($uri->host === $new_uri->host) return true; - $uri = $new_uri; // overwrite - return true; - } - - protected function makeReplace($uri, $config, $context) { - $string = $uri->toString(); - // always available - $this->replace['%s'] = $string; - $this->replace['%r'] = $context->get('EmbeddedURI', true); - $token = $context->get('CurrentToken', true); - $this->replace['%n'] = $token ? $token->name : null; - $this->replace['%m'] = $context->get('CurrentAttr', true); - $this->replace['%p'] = $context->get('CurrentCSSProperty', true); - // not always available - if ($this->secretKey) $this->replace['%t'] = sha1($this->secretKey . ':' . $string); - } - -} - -// vim: et sw=4 sts=4 diff --git a/modules/gallery/lib/HTMLPurifier/HTMLPurifier/URIParser.php b/modules/gallery/lib/HTMLPurifier/HTMLPurifier/URIParser.php deleted file mode 100644 index 902f5270..00000000 --- a/modules/gallery/lib/HTMLPurifier/HTMLPurifier/URIParser.php +++ /dev/null @@ -1,70 +0,0 @@ -percentEncoder = new HTMLPurifier_PercentEncoder(); - } - - /** - * Parses a URI. - * @param $uri string URI to parse - * @return HTMLPurifier_URI representation of URI. This representation has - * not been validated yet and may not conform to RFC. - */ - public function parse($uri) { - - $uri = $this->percentEncoder->normalize($uri); - - // Regexp is as per Appendix B. - // Note that ["<>] are an addition to the RFC's recommended - // characters, because they represent external delimeters. - $r_URI = '!'. - '(([^:/?#"<>]+):)?'. // 2. Scheme - '(//([^/?#"<>]*))?'. // 4. Authority - '([^?#"<>]*)'. // 5. Path - '(\?([^#"<>]*))?'. // 7. Query - '(#([^"<>]*))?'. // 8. Fragment - '!'; - - $matches = array(); - $result = preg_match($r_URI, $uri, $matches); - - if (!$result) return false; // *really* invalid URI - - // seperate out parts - $scheme = !empty($matches[1]) ? $matches[2] : null; - $authority = !empty($matches[3]) ? $matches[4] : null; - $path = $matches[5]; // always present, can be empty - $query = !empty($matches[6]) ? $matches[7] : null; - $fragment = !empty($matches[8]) ? $matches[9] : null; - - // further parse authority - if ($authority !== null) { - $r_authority = "/^((.+?)@)?(\[[^\]]+\]|[^:]*)(:(\d*))?/"; - $matches = array(); - preg_match($r_authority, $authority, $matches); - $userinfo = !empty($matches[1]) ? $matches[2] : null; - $host = !empty($matches[3]) ? $matches[3] : ''; - $port = !empty($matches[4]) ? (int) $matches[5] : null; - } else { - $port = $host = $userinfo = null; - } - - return new HTMLPurifier_URI( - $scheme, $userinfo, $host, $port, $path, $query, $fragment); - } - -} - -// vim: et sw=4 sts=4 diff --git a/modules/gallery/lib/HTMLPurifier/HTMLPurifier/URIScheme.php b/modules/gallery/lib/HTMLPurifier/HTMLPurifier/URIScheme.php deleted file mode 100644 index 2ef2ae55..00000000 --- a/modules/gallery/lib/HTMLPurifier/HTMLPurifier/URIScheme.php +++ /dev/null @@ -1,42 +0,0 @@ -, resolves edge cases - * with making relative URIs absolute - */ - public $hierarchical = false; - - /** - * Validates the components of a URI - * @note This implementation should be called by children if they define - * a default port, as it does port processing. - * @param $uri Instance of HTMLPurifier_URI - * @param $config HTMLPurifier_Config object - * @param $context HTMLPurifier_Context object - * @return Bool success or failure - */ - public function validate(&$uri, $config, $context) { - if ($this->default_port == $uri->port) $uri->port = null; - return true; - } - -} - -// vim: et sw=4 sts=4 diff --git a/modules/gallery/lib/HTMLPurifier/HTMLPurifier/URIScheme/ftp.php b/modules/gallery/lib/HTMLPurifier/HTMLPurifier/URIScheme/ftp.php deleted file mode 100644 index f86f5f27..00000000 --- a/modules/gallery/lib/HTMLPurifier/HTMLPurifier/URIScheme/ftp.php +++ /dev/null @@ -1,43 +0,0 @@ -query = null; - - // typecode check - $semicolon_pos = strrpos($uri->path, ';'); // reverse - if ($semicolon_pos !== false) { - $type = substr($uri->path, $semicolon_pos + 1); // no semicolon - $uri->path = substr($uri->path, 0, $semicolon_pos); - $type_ret = ''; - if (strpos($type, '=') !== false) { - // figure out whether or not the declaration is correct - list($key, $typecode) = explode('=', $type, 2); - if ($key !== 'type') { - // invalid key, tack it back on encoded - $uri->path .= '%3B' . $type; - } elseif ($typecode === 'a' || $typecode === 'i' || $typecode === 'd') { - $type_ret = ";type=$typecode"; - } - } else { - $uri->path .= '%3B' . $type; - } - $uri->path = str_replace(';', '%3B', $uri->path); - $uri->path .= $type_ret; - } - - return true; - } - -} - -// vim: et sw=4 sts=4 diff --git a/modules/gallery/lib/HTMLPurifier/HTMLPurifier/URIScheme/http.php b/modules/gallery/lib/HTMLPurifier/HTMLPurifier/URIScheme/http.php deleted file mode 100644 index 1a5ccbe9..00000000 --- a/modules/gallery/lib/HTMLPurifier/HTMLPurifier/URIScheme/http.php +++ /dev/null @@ -1,20 +0,0 @@ -userinfo = null; - return true; - } - -} - -// vim: et sw=4 sts=4 diff --git a/modules/gallery/lib/HTMLPurifier/HTMLPurifier/URIScheme/https.php b/modules/gallery/lib/HTMLPurifier/HTMLPurifier/URIScheme/https.php deleted file mode 100644 index ec1597bd..00000000 --- a/modules/gallery/lib/HTMLPurifier/HTMLPurifier/URIScheme/https.php +++ /dev/null @@ -1,12 +0,0 @@ -userinfo = null; - $uri->host = null; - $uri->port = null; - // we need to validate path against RFC 2368's addr-spec - return true; - } - -} - -// vim: et sw=4 sts=4 diff --git a/modules/gallery/lib/HTMLPurifier/HTMLPurifier/URIScheme/news.php b/modules/gallery/lib/HTMLPurifier/HTMLPurifier/URIScheme/news.php deleted file mode 100644 index 11a8f229..00000000 --- a/modules/gallery/lib/HTMLPurifier/HTMLPurifier/URIScheme/news.php +++ /dev/null @@ -1,22 +0,0 @@ -userinfo = null; - $uri->host = null; - $uri->port = null; - $uri->query = null; - // typecode check needed on path - return true; - } - -} - -// vim: et sw=4 sts=4 diff --git a/modules/gallery/lib/HTMLPurifier/HTMLPurifier/URIScheme/nntp.php b/modules/gallery/lib/HTMLPurifier/HTMLPurifier/URIScheme/nntp.php deleted file mode 100644 index 57a05451..00000000 --- a/modules/gallery/lib/HTMLPurifier/HTMLPurifier/URIScheme/nntp.php +++ /dev/null @@ -1,20 +0,0 @@ -userinfo = null; - $uri->query = null; - return true; - } - -} - -// vim: et sw=4 sts=4 diff --git a/modules/gallery/lib/HTMLPurifier/HTMLPurifier/URISchemeRegistry.php b/modules/gallery/lib/HTMLPurifier/HTMLPurifier/URISchemeRegistry.php deleted file mode 100644 index ad227a43..00000000 --- a/modules/gallery/lib/HTMLPurifier/HTMLPurifier/URISchemeRegistry.php +++ /dev/null @@ -1,68 +0,0 @@ -get('URI.AllowedSchemes'); - if (!$config->get('URI.OverrideAllowedSchemes') && - !isset($allowed_schemes[$scheme]) - ) { - return; - } - - if (isset($this->schemes[$scheme])) return $this->schemes[$scheme]; - if (!isset($allowed_schemes[$scheme])) return; - - $class = 'HTMLPurifier_URIScheme_' . $scheme; - if (!class_exists($class)) return; - $this->schemes[$scheme] = new $class(); - return $this->schemes[$scheme]; - } - - /** - * Registers a custom scheme to the cache, bypassing reflection. - * @param $scheme Scheme name - * @param $scheme_obj HTMLPurifier_URIScheme object - */ - public function register($scheme, $scheme_obj) { - $this->schemes[$scheme] = $scheme_obj; - } - -} - -// vim: et sw=4 sts=4 diff --git a/modules/gallery/lib/HTMLPurifier/HTMLPurifier/UnitConverter.php b/modules/gallery/lib/HTMLPurifier/HTMLPurifier/UnitConverter.php deleted file mode 100644 index 1944fad9..00000000 --- a/modules/gallery/lib/HTMLPurifier/HTMLPurifier/UnitConverter.php +++ /dev/null @@ -1,254 +0,0 @@ - array( - 'px' => 3, // This is as per CSS 2.1 and Firefox. Your mileage may vary - 'pt' => 4, - 'pc' => 48, - 'in' => 288, - self::METRIC => array('pt', '0.352777778', 'mm'), - ), - self::METRIC => array( - 'mm' => 1, - 'cm' => 10, - self::ENGLISH => array('mm', '2.83464567', 'pt'), - ), - ); - - /** - * Minimum bcmath precision for output. - */ - protected $outputPrecision; - - /** - * Bcmath precision for internal calculations. - */ - protected $internalPrecision; - - /** - * Whether or not BCMath is available - */ - private $bcmath; - - public function __construct($output_precision = 4, $internal_precision = 10, $force_no_bcmath = false) { - $this->outputPrecision = $output_precision; - $this->internalPrecision = $internal_precision; - $this->bcmath = !$force_no_bcmath && function_exists('bcmul'); - } - - /** - * Converts a length object of one unit into another unit. - * @param HTMLPurifier_Length $length - * Instance of HTMLPurifier_Length to convert. You must validate() - * it before passing it here! - * @param string $to_unit - * Unit to convert to. - * @note - * About precision: This conversion function pays very special - * attention to the incoming precision of values and attempts - * to maintain a number of significant figure. Results are - * fairly accurate up to nine digits. Some caveats: - * - If a number is zero-padded as a result of this significant - * figure tracking, the zeroes will be eliminated. - * - If a number contains less than four sigfigs ($outputPrecision) - * and this causes some decimals to be excluded, those - * decimals will be added on. - */ - public function convert($length, $to_unit) { - - if (!$length->isValid()) return false; - - $n = $length->getN(); - $unit = $length->getUnit(); - - if ($n === '0' || $unit === false) { - return new HTMLPurifier_Length('0', false); - } - - $state = $dest_state = false; - foreach (self::$units as $k => $x) { - if (isset($x[$unit])) $state = $k; - if (isset($x[$to_unit])) $dest_state = $k; - } - if (!$state || !$dest_state) return false; - - // Some calculations about the initial precision of the number; - // this will be useful when we need to do final rounding. - $sigfigs = $this->getSigFigs($n); - if ($sigfigs < $this->outputPrecision) $sigfigs = $this->outputPrecision; - - // BCMath's internal precision deals only with decimals. Use - // our default if the initial number has no decimals, or increase - // it by how ever many decimals, thus, the number of guard digits - // will always be greater than or equal to internalPrecision. - $log = (int) floor(log(abs($n), 10)); - $cp = ($log < 0) ? $this->internalPrecision - $log : $this->internalPrecision; // internal precision - - for ($i = 0; $i < 2; $i++) { - - // Determine what unit IN THIS SYSTEM we need to convert to - if ($dest_state === $state) { - // Simple conversion - $dest_unit = $to_unit; - } else { - // Convert to the smallest unit, pending a system shift - $dest_unit = self::$units[$state][$dest_state][0]; - } - - // Do the conversion if necessary - if ($dest_unit !== $unit) { - $factor = $this->div(self::$units[$state][$unit], self::$units[$state][$dest_unit], $cp); - $n = $this->mul($n, $factor, $cp); - $unit = $dest_unit; - } - - // Output was zero, so bail out early. Shouldn't ever happen. - if ($n === '') { - $n = '0'; - $unit = $to_unit; - break; - } - - // It was a simple conversion, so bail out - if ($dest_state === $state) { - break; - } - - if ($i !== 0) { - // Conversion failed! Apparently, the system we forwarded - // to didn't have this unit. This should never happen! - return false; - } - - // Pre-condition: $i == 0 - - // Perform conversion to next system of units - $n = $this->mul($n, self::$units[$state][$dest_state][1], $cp); - $unit = self::$units[$state][$dest_state][2]; - $state = $dest_state; - - // One more loop around to convert the unit in the new system. - - } - - // Post-condition: $unit == $to_unit - if ($unit !== $to_unit) return false; - - // Useful for debugging: - //echo "
                n";
                -        //echo "$n\nsigfigs = $sigfigs\nnew_log = $new_log\nlog = $log\nrp = $rp\n
                \n"; - - $n = $this->round($n, $sigfigs); - if (strpos($n, '.') !== false) $n = rtrim($n, '0'); - $n = rtrim($n, '.'); - - return new HTMLPurifier_Length($n, $unit); - } - - /** - * Returns the number of significant figures in a string number. - * @param string $n Decimal number - * @return int number of sigfigs - */ - public function getSigFigs($n) { - $n = ltrim($n, '0+-'); - $dp = strpos($n, '.'); // decimal position - if ($dp === false) { - $sigfigs = strlen(rtrim($n, '0')); - } else { - $sigfigs = strlen(ltrim($n, '0.')); // eliminate extra decimal character - if ($dp !== 0) $sigfigs--; - } - return $sigfigs; - } - - /** - * Adds two numbers, using arbitrary precision when available. - */ - private function add($s1, $s2, $scale) { - if ($this->bcmath) return bcadd($s1, $s2, $scale); - else return $this->scale($s1 + $s2, $scale); - } - - /** - * Multiples two numbers, using arbitrary precision when available. - */ - private function mul($s1, $s2, $scale) { - if ($this->bcmath) return bcmul($s1, $s2, $scale); - else return $this->scale($s1 * $s2, $scale); - } - - /** - * Divides two numbers, using arbitrary precision when available. - */ - private function div($s1, $s2, $scale) { - if ($this->bcmath) return bcdiv($s1, $s2, $scale); - else return $this->scale($s1 / $s2, $scale); - } - - /** - * Rounds a number according to the number of sigfigs it should have, - * using arbitrary precision when available. - */ - private function round($n, $sigfigs) { - $new_log = (int) floor(log(abs($n), 10)); // Number of digits left of decimal - 1 - $rp = $sigfigs - $new_log - 1; // Number of decimal places needed - $neg = $n < 0 ? '-' : ''; // Negative sign - if ($this->bcmath) { - if ($rp >= 0) { - $n = bcadd($n, $neg . '0.' . str_repeat('0', $rp) . '5', $rp + 1); - $n = bcdiv($n, '1', $rp); - } else { - // This algorithm partially depends on the standardized - // form of numbers that comes out of bcmath. - $n = bcadd($n, $neg . '5' . str_repeat('0', $new_log - $sigfigs), 0); - $n = substr($n, 0, $sigfigs + strlen($neg)) . str_repeat('0', $new_log - $sigfigs + 1); - } - return $n; - } else { - return $this->scale(round($n, $sigfigs - $new_log - 1), $rp + 1); - } - } - - /** - * Scales a float to $scale digits right of decimal point, like BCMath. - */ - private function scale($r, $scale) { - if ($scale < 0) { - // The f sprintf type doesn't support negative numbers, so we - // need to cludge things manually. First get the string. - $r = sprintf('%.0f', (float) $r); - // Due to floating point precision loss, $r will more than likely - // look something like 4652999999999.9234. We grab one more digit - // than we need to precise from $r and then use that to round - // appropriately. - $precise = (string) round(substr($r, 0, strlen($r) + $scale), -1); - // Now we return it, truncating the zero that was rounded off. - return substr($precise, 0, -1) . str_repeat('0', -$scale + 1); - } - return sprintf('%.' . $scale . 'f', (float) $r); - } - -} - -// vim: et sw=4 sts=4 diff --git a/modules/gallery/lib/HTMLPurifier/HTMLPurifier/VarParser.php b/modules/gallery/lib/HTMLPurifier/HTMLPurifier/VarParser.php deleted file mode 100644 index f5dbb536..00000000 --- a/modules/gallery/lib/HTMLPurifier/HTMLPurifier/VarParser.php +++ /dev/null @@ -1,154 +0,0 @@ - self::STRING, - 'istring' => self::ISTRING, - 'text' => self::TEXT, - 'itext' => self::ITEXT, - 'int' => self::INT, - 'float' => self::FLOAT, - 'bool' => self::BOOL, - 'lookup' => self::LOOKUP, - 'list' => self::ALIST, - 'hash' => self::HASH, - 'mixed' => self::MIXED - ); - - /** - * Lookup table of types that are string, and can have aliases or - * allowed value lists. - */ - static public $stringTypes = array( - self::STRING => true, - self::ISTRING => true, - self::TEXT => true, - self::ITEXT => true, - ); - - /** - * Validate a variable according to type. Throws - * HTMLPurifier_VarParserException if invalid. - * It may return NULL as a valid type if $allow_null is true. - * - * @param $var Variable to validate - * @param $type Type of variable, see HTMLPurifier_VarParser->types - * @param $allow_null Whether or not to permit null as a value - * @return Validated and type-coerced variable - */ - final public function parse($var, $type, $allow_null = false) { - if (is_string($type)) { - if (!isset(HTMLPurifier_VarParser::$types[$type])) { - throw new HTMLPurifier_VarParserException("Invalid type '$type'"); - } else { - $type = HTMLPurifier_VarParser::$types[$type]; - } - } - $var = $this->parseImplementation($var, $type, $allow_null); - if ($allow_null && $var === null) return null; - // These are basic checks, to make sure nothing horribly wrong - // happened in our implementations. - switch ($type) { - case (self::STRING): - case (self::ISTRING): - case (self::TEXT): - case (self::ITEXT): - if (!is_string($var)) break; - if ($type == self::ISTRING || $type == self::ITEXT) $var = strtolower($var); - return $var; - case (self::INT): - if (!is_int($var)) break; - return $var; - case (self::FLOAT): - if (!is_float($var)) break; - return $var; - case (self::BOOL): - if (!is_bool($var)) break; - return $var; - case (self::LOOKUP): - case (self::ALIST): - case (self::HASH): - if (!is_array($var)) break; - if ($type === self::LOOKUP) { - foreach ($var as $k) if ($k !== true) $this->error('Lookup table contains value other than true'); - } elseif ($type === self::ALIST) { - $keys = array_keys($var); - if (array_keys($keys) !== $keys) $this->error('Indices for list are not uniform'); - } - return $var; - case (self::MIXED): - return $var; - default: - $this->errorInconsistent(get_class($this), $type); - } - $this->errorGeneric($var, $type); - } - - /** - * Actually implements the parsing. Base implementation is to not - * do anything to $var. Subclasses should overload this! - */ - protected function parseImplementation($var, $type, $allow_null) { - return $var; - } - - /** - * Throws an exception. - */ - protected function error($msg) { - throw new HTMLPurifier_VarParserException($msg); - } - - /** - * Throws an inconsistency exception. - * @note This should not ever be called. It would be called if we - * extend the allowed values of HTMLPurifier_VarParser without - * updating subclasses. - */ - protected function errorInconsistent($class, $type) { - throw new HTMLPurifier_Exception("Inconsistency in $class: ".HTMLPurifier_VarParser::getTypeName($type)." not implemented"); - } - - /** - * Generic error for if a type didn't work. - */ - protected function errorGeneric($var, $type) { - $vtype = gettype($var); - $this->error("Expected type ".HTMLPurifier_VarParser::getTypeName($type).", got $vtype"); - } - - static public function getTypeName($type) { - static $lookup; - if (!$lookup) { - // Lazy load the alternative lookup table - $lookup = array_flip(HTMLPurifier_VarParser::$types); - } - if (!isset($lookup[$type])) return 'unknown'; - return $lookup[$type]; - } - -} - -// vim: et sw=4 sts=4 diff --git a/modules/gallery/lib/HTMLPurifier/HTMLPurifier/VarParser/Flexible.php b/modules/gallery/lib/HTMLPurifier/HTMLPurifier/VarParser/Flexible.php deleted file mode 100644 index e5998e5e..00000000 --- a/modules/gallery/lib/HTMLPurifier/HTMLPurifier/VarParser/Flexible.php +++ /dev/null @@ -1,96 +0,0 @@ - $j) $var[$i] = trim($j); - if ($type === self::HASH) { - // key:value,key2:value2 - $nvar = array(); - foreach ($var as $keypair) { - $c = explode(':', $keypair, 2); - if (!isset($c[1])) continue; - $nvar[$c[0]] = $c[1]; - } - $var = $nvar; - } - } - if (!is_array($var)) break; - $keys = array_keys($var); - if ($keys === array_keys($keys)) { - if ($type == self::ALIST) return $var; - elseif ($type == self::LOOKUP) { - $new = array(); - foreach ($var as $key) { - $new[$key] = true; - } - return $new; - } else break; - } - if ($type === self::LOOKUP) { - foreach ($var as $key => $value) { - $var[$key] = true; - } - } - return $var; - default: - $this->errorInconsistent(__CLASS__, $type); - } - $this->errorGeneric($var, $type); - } - -} - -// vim: et sw=4 sts=4 diff --git a/modules/gallery/lib/HTMLPurifier/HTMLPurifier/VarParser/Native.php b/modules/gallery/lib/HTMLPurifier/HTMLPurifier/VarParser/Native.php deleted file mode 100644 index cdd342fa..00000000 --- a/modules/gallery/lib/HTMLPurifier/HTMLPurifier/VarParser/Native.php +++ /dev/null @@ -1,26 +0,0 @@ -evalExpression($var); - } - - protected function evalExpression($expr) { - $var = null; - $result = eval("\$var = $expr;"); - if ($result === false) { - throw new HTMLPurifier_VarParserException("Fatal error in evaluated code"); - } - return $var; - } - -} - -// vim: et sw=4 sts=4 diff --git a/modules/gallery/lib/HTMLPurifier/HTMLPurifier/VarParserException.php b/modules/gallery/lib/HTMLPurifier/HTMLPurifier/VarParserException.php deleted file mode 100644 index fe30cc79..00000000 --- a/modules/gallery/lib/HTMLPurifier/HTMLPurifier/VarParserException.php +++ /dev/null @@ -1,11 +0,0 @@ - - Copyright (C) - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library 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 - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - -Also add information on how to contact you by electronic and paper mail. - -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the library, if -necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the - library `Frob' (a library for tweaking knobs) written by James Random Hacker. - - , 1 April 1990 - Ty Coon, President of Vice - -That's all there is to it! - - vim: et sw=4 sts=4 diff --git a/modules/gallery/libraries/HtmlPurifier.php b/modules/gallery/libraries/HtmlPurifier.php deleted file mode 100644 index daa5896e..00000000 --- a/modules/gallery/libraries/HtmlPurifier.php +++ /dev/null @@ -1,38 +0,0 @@ - $key_value) { - foreach ($key_value as $key => $value) { - $purifier_config->set("$category.$key", $value); - } - } - self::$_instance = new HtmlPurifier($purifier_config); - } - - return self::$_instance; - } -} diff --git a/modules/gallery/libraries/SafeString.php b/modules/gallery/libraries/SafeString.php index cc542e01..32ef1905 100644 --- a/modules/gallery/libraries/SafeString.php +++ b/modules/gallery/libraries/SafeString.php @@ -83,7 +83,7 @@ class SafeString_Core { * Safe for use in HTML. * * Example:
                -   *   
                + *
                *
                * @return the string escaped for use in HTML. */ @@ -128,7 +128,7 @@ class SafeString_Core { * Safe for use HTML (purified HTML) * * Example:
                -   *   
                purified_html() ?> + *
                purified_html() ?> *
                * @return the string escaped for use in HTML. */ @@ -154,16 +154,22 @@ class SafeString_Core { // Purifies the string, removing any potentially malicious or unsafe HTML / JavaScript. private static function _purify_for_html($dirty_html) { - if (empty(self::$_purifier)) { - require_once(dirname(__file__) . "/../lib/HTMLPurifier/HTMLPurifier.auto.php"); - $config = HTMLPurifier_Config::createDefault(); - foreach (Kohana::config('purifier') as $category => $key_value) { - foreach ($key_value as $key => $value) { - $config->set("$category.$key", $value); + if (module::is_active("htmlpurifier")) { + if (empty(self::$_purifier)) { + require_once(MODPATH . "htmlpurifier/lib/HTMLPurifier/HTMLPurifier.auto.php"); + $config = HTMLPurifier_Config::createDefault(); + foreach (Kohana::config('purifier') as $category => $key_value) { + foreach ($key_value as $key => $value) { + $config->set("$category.$key", $value); + } } + self::$_purifier = new HTMLPurifier($config); } - self::$_purifier = new HTMLPurifier($config); + Kohana::log("error", "Purify: " . $dirty_html); + return self::$_purifier->purify($dirty_html); + } else { + Kohana::log("error", "revert to clean: " . $dirty_html); + return self::_escape_for_html($dirty_html); } - return self::$_purifier->purify($dirty_html); } } -- cgit v1.2.3 From f2bbb2963a03c7f838772fa89facc0e38c3e4f4e Mon Sep 17 00:00:00 2001 From: Tim Almdal Date: Wed, 2 Sep 2009 07:07:47 -0700 Subject: Remove debugging statementes --- modules/gallery/libraries/SafeString.php | 2 -- 1 file changed, 2 deletions(-) diff --git a/modules/gallery/libraries/SafeString.php b/modules/gallery/libraries/SafeString.php index 32ef1905..800647fa 100644 --- a/modules/gallery/libraries/SafeString.php +++ b/modules/gallery/libraries/SafeString.php @@ -165,10 +165,8 @@ class SafeString_Core { } self::$_purifier = new HTMLPurifier($config); } - Kohana::log("error", "Purify: " . $dirty_html); return self::$_purifier->purify($dirty_html); } else { - Kohana::log("error", "revert to clean: " . $dirty_html); return self::_escape_for_html($dirty_html); } } -- cgit v1.2.3 From a09a6a06bef1ff08e09a2855b308e20ea739ca1e Mon Sep 17 00:00:00 2001 From: Bharat Mediratta Date: Wed, 2 Sep 2009 11:28:41 -0700 Subject: Refactor how we use $this->relative_path() so that we're not calling it twice on both sides of a ternary operator. --- modules/gallery/models/item.php | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/modules/gallery/models/item.php b/modules/gallery/models/item.php index 68e89db6..8905a627 100644 --- a/modules/gallery/models/item.php +++ b/modules/gallery/models/item.php @@ -188,9 +188,8 @@ class Item_Model extends ORM_MPTT { * photo: http://example.com/gallery3/var/albums/album1/photo.jpg */ public function file_url($full_uri=false) { - return $full_uri ? - url::abs_file("var/albums/" . $this->relative_path()) : - url::file("var/albums/" . $this->relative_path()); + $relative_path = "var/albums/" . $this->relative_path(); + return $full_uri ? url::abs_file($relative_path) : url::file($relative_path); } /** @@ -222,9 +221,8 @@ class Item_Model extends ORM_MPTT { */ public function thumb_url($full_uri=false) { $cache_buster = "?m=" . $this->updated; - $base = ($full_uri ? - url::abs_file("var/thumbs/" . $this->relative_path()) : - url::file("var/thumbs/" . $this->relative_path())); + $relative_path = "var/thumbs/" . $this->relative_path(); + $base = ($full_uri ? url::abs_file($relative_path) : url::file($relative_path)); if ($this->is_photo()) { return $base . $cache_buster; } else if ($this->is_album()) { @@ -250,9 +248,8 @@ class Item_Model extends ORM_MPTT { * photo: http://example.com/gallery3/var/albums/album1/photo.resize.jpg */ public function resize_url($full_uri=false) { - return ($full_uri ? - url::abs_file("var/resizes/" . $this->relative_path()) : - url::file("var/resizes/" . $this->relative_path())) . + $relative_path = "var/resizes/" . $this->relative_path(); + return ($full_uri ? url::abs_file($relative_path) : url::file($relative_path)) . ($this->is_album() ? "/.album.jpg" : ""); } -- cgit v1.2.3 From 79754c2ef477c98740166a2a86fb491e0b07944e Mon Sep 17 00:00:00 2001 From: Bharat Mediratta Date: Wed, 2 Sep 2009 11:53:10 -0700 Subject: Run 'graphics::choose_default_toolkit();' to pick a toolkit, which we normally do as part of a regular install. --- modules/gallery_unit_test/controllers/gallery_unit_test.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/modules/gallery_unit_test/controllers/gallery_unit_test.php b/modules/gallery_unit_test/controllers/gallery_unit_test.php index 8f3353dc..a5dbcc1f 100644 --- a/modules/gallery_unit_test/controllers/gallery_unit_test.php +++ b/modules/gallery_unit_test/controllers/gallery_unit_test.php @@ -122,6 +122,9 @@ class Gallery_Unit_Test_Controller extends Controller { module::activate($module_name); } + // Trigger late-binding install actions (defined in gallery_event::user_login) + graphics::choose_default_toolkit(); + $filter = count($_SERVER["argv"]) > 2 ? $_SERVER["argv"][2] : null; print new Unit_Test($modules, $filter); } catch (Exception $e) { -- cgit v1.2.3 From b9293755c03a6bf55a33732968481aa7a73fcce0 Mon Sep 17 00:00:00 2001 From: Bharat Mediratta Date: Wed, 2 Sep 2009 11:57:20 -0700 Subject: Deal with the aftermath of adding sharpen() calls. Since GD does not support it, this causes crashes as soon as you try to use it, which breaks a bunch of our tests. Also, give the user some idea that sharpen() is missing in the UI. Fixes #689. --- modules/gallery/helpers/graphics.php | 37 ++++++++++++++++++++++++++---------- 1 file changed, 27 insertions(+), 10 deletions(-) diff --git a/modules/gallery/helpers/graphics.php b/modules/gallery/helpers/graphics.php index 521dc5a4..66182a68 100644 --- a/modules/gallery/helpers/graphics.php +++ b/modules/gallery/helpers/graphics.php @@ -206,11 +206,13 @@ class graphics_Core { // Image would get upscaled; do nothing copy($input_file, $output_file); } else { - Image::factory($input_file) + $image = Image::factory($input_file) ->resize($options["width"], $options["height"], $options["master"]) - ->quality(module::get_var("gallery", "image_quality")) - ->sharpen(module::get_var("gallery", "image_sharpen")) - ->save($output_file); + ->quality(module::get_var("gallery", "image_quality")); + if (graphics::can("sharpen")) { + $image->sharpen(module::get_var("gallery", "image_sharpen")); + } + $image->save($output_file); } module::event("graphics_resize_completed", $input_file, $output_file, $options); @@ -352,13 +354,22 @@ class graphics_Core { $toolkits->gd->installed = true; $toolkits->gd->version = $gd["GD Version"]; $toolkits->gd->rotate = function_exists("imagerotate"); + $toolkits->gd->sharpen = function_exists("imageconvolution"); $toolkits->gd->binary = ""; $toolkits->gd->dir = ""; - if (!$toolkits->gd->rotate) { + if (!$toolkits->gd->rotate && !$toolkits->gd->sharpen) { + $toolkits->gd->error = + t("You have GD version %version, but it lacks image rotation and sharpening.", + array("version" => $gd["GD Version"])); + } else if (!$toolkits->gd->rotate) { $toolkits->gd->error = t("You have GD version %version, but it lacks image rotation.", array("version" => $gd["GD Version"])); + } else if (!$toolkits->gd->sharpen) { + $toolkits->gd->error = + t("You have GD version %version, but it lacks image sharpening.", + array("version" => $gd["GD Version"])); } } @@ -387,6 +398,7 @@ class graphics_Core { $toolkits->imagemagick->binary = $path; $toolkits->imagemagick->dir = dirname($path); $toolkits->imagemagick->rotate = true; + $toolkits->imagemagick->sharpen = true; } else { $toolkits->imagemagick->installed = false; $toolkits->imagemagick->error = @@ -411,6 +423,7 @@ class graphics_Core { $toolkits->graphicsmagick->binary = $path; $toolkits->graphicsmagick->dir = dirname($path); $toolkits->graphicsmagick->rotate = true; + $toolkits->graphicsmagick->sharpen = true; } else { $toolkits->graphicsmagick->installed = false; $toolkits->graphicsmagick->error = @@ -475,14 +488,18 @@ class graphics_Core { /** * Verify that a specific graphics function is available with the active toolkit. - * @param string $func (eg rotate, resize) + * @param string $func (eg rotate, sharpen) * @return boolean */ static function can($func) { - if (module::get_var("gallery", "graphics_toolkit") == "gd" && - $func == "rotate" && - !function_exists("imagerotate")) { - return false; + if (module::get_var("gallery", "graphics_toolkit") == "gd") { + switch ($func) { + case "rotate": + return function_exists("imagerotate"); + + case "sharpen": + return function_exists("imageconvolution"); + } } return true; -- cgit v1.2.3 From b842a9d9ca21d07241b5fa11c5263e18f830c88b Mon Sep 17 00:00:00 2001 From: Bharat Mediratta Date: Wed, 2 Sep 2009 11:58:04 -0700 Subject: Fix formatting, and use a properly named file in change_photo_no_csrf_fails_test() so that GD doesn't bomb. --- modules/gallery/tests/Photos_Controller_Test.php | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/modules/gallery/tests/Photos_Controller_Test.php b/modules/gallery/tests/Photos_Controller_Test.php index f7d3f72f..5c4802c2 100644 --- a/modules/gallery/tests/Photos_Controller_Test.php +++ b/modules/gallery/tests/Photos_Controller_Test.php @@ -33,8 +33,8 @@ class Photos_Controller_Test extends Unit_Test_Case { public function change_photo_test() { $controller = new Photos_Controller(); $root = ORM::factory("item", 1); - $this->_photo = photo::create($root, MODPATH . "gallery/tests/test.jpg", "test.jpeg", "test", - "test"); + $this->_photo = photo::create( + $root, MODPATH . "gallery/tests/test.jpg", "test.jpeg", "test", "test"); $orig_name = $this->_photo->name; $_POST["filename"] = "test.jpeg"; @@ -63,7 +63,8 @@ class Photos_Controller_Test extends Unit_Test_Case { public function change_photo_no_csrf_fails_test() { $controller = new Photos_Controller(); $root = ORM::factory("item", 1); - $this->_photo = photo::create($root, MODPATH . "gallery/tests/test.jpg", "test", "test", "test"); + $this->_photo = photo::create( + $root, MODPATH . "gallery/tests/test.jpg", "test.jpg", "test", "test"); $_POST["name"] = "new name"; $_POST["title"] = "new title"; $_POST["description"] = "new description"; -- cgit v1.2.3 From 417c983491a7708a1d60e909caead239ef02eadd Mon Sep 17 00:00:00 2001 From: Bharat Mediratta Date: Wed, 2 Sep 2009 20:04:11 -0700 Subject: Tighten up the mod_rewrite text a bit. --- .htaccess | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/.htaccess b/.htaccess index c3f94237..8c2e3793 100644 --- a/.htaccess +++ b/.htaccess @@ -29,13 +29,12 @@ # ExpiresByType text/html A1 # -# You can use mod_rewrite to enable short urls in Gallery 3 (which -# gets rid of the "index.php" from your urls). To do this, you must -# uncomment the block below that starts with and ends with -# then properly configure the RewriteBase line in the -# block below. You just need to change RewriteBase line to match your -# Gallery 3 URL. Here are some examples: +# You can use the mod_rewrite Apache module to get rid of the +# "index.php" from your Gallery 3 urls. Uncomment the block below +# inside the ... lines and then edit the +# RewriteBase line to match your Gallery 3 URL. # +# Here are some RewriteBase values: # Gallery 3 URL RewriteBase line # ============= ==================== # http://example.com/gallery3 RewriteBase /gallery3 @@ -45,9 +44,8 @@ # Then just use your Gallery 3 without the index.php in the url. # # NOTE: future upgrades of Gallery 3 will overwrite this file! If you -# want these changes to be persistent, you should talk to your system -# administrator about putting this block into your Apache config -# files. +# want these changes to be persistent, talk to your system admin about +# putting this block into your Apache config files. # # # RewriteEngine On -- cgit v1.2.3 From 2c30dc2d5b451ebd5623becd71c42b43be91d0b9 Mon Sep 17 00:00:00 2001 From: Tim Almdal Date: Wed, 2 Sep 2009 14:28:00 -0700 Subject: fix a leading space that was causing the file_structure_test to fail --- modules/gallery/controllers/albums.php | 38 +++++++++++++++++----------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/modules/gallery/controllers/albums.php b/modules/gallery/controllers/albums.php index 8ceff0f9..627ee052 100644 --- a/modules/gallery/controllers/albums.php +++ b/modules/gallery/controllers/albums.php @@ -1,22 +1,22 @@ - Date: Wed, 2 Sep 2009 15:29:00 -0700 Subject: Change graphics::generate() API so that it doesn't return a boolean, instead it throws an exception if there's a problem. The normal case for graphics::generate is that it's going to succeed. It'll only fail if something un-handleable went wrong, so just use the resulting exception. --- modules/gallery/helpers/gallery_task.php | 11 ++++++----- modules/gallery/helpers/graphics.php | 10 ++++------ modules/gallery/helpers/photo.php | 6 ++++-- 3 files changed, 14 insertions(+), 13 deletions(-) diff --git a/modules/gallery/helpers/gallery_task.php b/modules/gallery/helpers/gallery_task.php index c9557324..1b56ab97 100644 --- a/modules/gallery/helpers/gallery_task.php +++ b/modules/gallery/helpers/gallery_task.php @@ -60,14 +60,15 @@ class gallery_task_Core { $item = ORM::factory("item", $row->id); if ($item->loaded) { - $success = graphics::generate($item); - if (!$success) { + try { + graphics::generate($item); $ignored[$item->id] = 1; - $errors[] = t("Unable to rebuild images for '%title'", - array("title" => html::purify($item->title))); - } else { $errors[] = t("Successfully rebuilt images for '%title'", array("title" => html::purify($item->title))); + } catch (Exception $e) { + $errors[] = t("Unable to rebuild images for '%title'", + array("title" => html::purify($item->title))); + $errors[] = $e->__toString(); } } diff --git a/modules/gallery/helpers/graphics.php b/modules/gallery/helpers/graphics.php index 66182a68..78812794 100644 --- a/modules/gallery/helpers/graphics.php +++ b/modules/gallery/helpers/graphics.php @@ -102,12 +102,12 @@ class graphics_Core { /** * Rebuild the thumb and resize for the given item. * @param Item_Model $item - * @return true on successful generation */ static function generate($item) { if ($item->is_album()) { if (!$cover = $item->album_cover()) { - return false; + // This album has no cover; there's nothing to generate. + return; } $input_file = $cover->file_path(); $input_item = $cover; @@ -127,7 +127,7 @@ class graphics_Core { $item->thumb_dirty = 0; $item->resize_dirty = 0; $item->save(); - return true; + return; } try { @@ -176,10 +176,8 @@ class graphics_Core { // @todo we should handle this better. Kohana::log("error", "Caught exception rebuilding image: {$item->title}\n" . $e->getMessage() . "\n" . $e->getTraceAsString()); - return false; + throw $e; } - - return true; } /** diff --git a/modules/gallery/helpers/photo.php b/modules/gallery/helpers/photo.php index 96a66d29..40b645a2 100644 --- a/modules/gallery/helpers/photo.php +++ b/modules/gallery/helpers/photo.php @@ -111,9 +111,11 @@ class photo_Core { // Build our thumbnail/resizes. If we fail to build thumbnail/resize we assume that the image // is bad in some way and discard it. - if (!graphics::generate($photo)) { + try { + graphics::generate($photo); + } catch (Exception $e) { $photo->delete(); - throw new Exception("@todo BAD_IMAGE_FILE"); + throw $e; } // If the parent has no cover item, make this it. -- cgit v1.2.3 From d007f31686e182e65cd18806ad3e4e29614fec81 Mon Sep 17 00:00:00 2001 From: Bharat Mediratta Date: Wed, 2 Sep 2009 21:29:22 -0700 Subject: Undo rest of the indentation issue accidentally created in 8312eb and partially fixed in 2c30dc --- modules/gallery/controllers/albums.php | 192 ++++++++++++++++----------------- 1 file changed, 96 insertions(+), 96 deletions(-) diff --git a/modules/gallery/controllers/albums.php b/modules/gallery/controllers/albums.php index 627ee052..5f62f798 100644 --- a/modules/gallery/controllers/albums.php +++ b/modules/gallery/controllers/albums.php @@ -17,102 +17,102 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ - class Albums_Controller extends Items_Controller { - - /** - * @see REST_Controller::_show($resource) - */ - public function _show($album) { - $page_size = module::get_var("gallery", "page_size", 9); - if (!access::can("view", $album)) { - if ($album->id == 1) { - $view = new Theme_View("page.html", "login"); - $view->page_title = t("Log in to Gallery"); - $view->content = user::get_login_form("login/auth_html"); - print $view; - return; - } else { - access::forbidden(); - } - } - - $show = $this->input->get("show"); - - if ($show) { - $index = $album->get_position($show); - $page = ceil($index / $page_size); - if ($page == 1) { - url::redirect("albums/$album->id"); - } else { - url::redirect("albums/$album->id?page=$page"); - } - } - - $page = $this->input->get("page", "1"); - $children_count = $album->viewable()->children_count(); - $offset = ($page - 1) * $page_size; - $max_pages = max(ceil($children_count / $page_size), 1); - - // Make sure that the page references a valid offset - if ($page < 1) { - url::redirect("albums/$album->id"); - } else if ($page > $max_pages) { - url::redirect("albums/$album->id?page=$max_pages"); - } - - $template = new Theme_View("page.html", "album"); - $template->set_global("page_size", $page_size); - $template->set_global("item", $album); - $template->set_global("children", $album->viewable()->children($page_size, $offset)); - $template->set_global("children_count", $children_count); - $template->set_global("parents", $album->parents()); - $template->content = new View("album.html"); - - // We can't use math in ORM or the query builder, so do this by hand. It's important - // that we do this with math, otherwise concurrent accesses will damage accuracy. - Database::instance()->query( - "UPDATE {items} SET `view_count` = `view_count` + 1 WHERE `id` = $album->id"); - - print $template; - } - - /** - * @see REST_Controller::_create($resource) - */ - public function _create($album) { - access::verify_csrf(); - access::required("view", $album); - access::required("add", $album); - - switch ($this->input->post("type")) { - case "album": - return $this->_create_album($album); - - case "photo": - return $this->_create_photo($album); - - default: - access::forbidden(); - } - } - - private function _create_album($album) { - access::required("view", $album); - access::required("add", $album); - - $form = album::get_add_form($album); - if ($form->validate()) { - $new_album = album::create( - $album, - $this->input->post("name"), - $this->input->post("title", $this->input->post("name")), - $this->input->post("description"), - user::active()->id); - - log::success("content", "Created an album", - html::anchor("albums/$new_album->id", "view album")); - message::success(t("Created album %album_title", - array("album_title" => html::purify($new_album->title)))); +class Albums_Controller extends Items_Controller { + + /** + * @see REST_Controller::_show($resource) + */ + public function _show($album) { + $page_size = module::get_var("gallery", "page_size", 9); + if (!access::can("view", $album)) { + if ($album->id == 1) { + $view = new Theme_View("page.html", "login"); + $view->page_title = t("Log in to Gallery"); + $view->content = user::get_login_form("login/auth_html"); + print $view; + return; + } else { + access::forbidden(); + } + } + + $show = $this->input->get("show"); + + if ($show) { + $index = $album->get_position($show); + $page = ceil($index / $page_size); + if ($page == 1) { + url::redirect("albums/$album->id"); + } else { + url::redirect("albums/$album->id?page=$page"); + } + } + + $page = $this->input->get("page", "1"); + $children_count = $album->viewable()->children_count(); + $offset = ($page - 1) * $page_size; + $max_pages = max(ceil($children_count / $page_size), 1); + + // Make sure that the page references a valid offset + if ($page < 1) { + url::redirect("albums/$album->id"); + } else if ($page > $max_pages) { + url::redirect("albums/$album->id?page=$max_pages"); + } + + $template = new Theme_View("page.html", "album"); + $template->set_global("page_size", $page_size); + $template->set_global("item", $album); + $template->set_global("children", $album->viewable()->children($page_size, $offset)); + $template->set_global("children_count", $children_count); + $template->set_global("parents", $album->parents()); + $template->content = new View("album.html"); + + // We can't use math in ORM or the query builder, so do this by hand. It's important + // that we do this with math, otherwise concurrent accesses will damage accuracy. + Database::instance()->query( + "UPDATE {items} SET `view_count` = `view_count` + 1 WHERE `id` = $album->id"); + + print $template; + } + + /** + * @see REST_Controller::_create($resource) + */ + public function _create($album) { + access::verify_csrf(); + access::required("view", $album); + access::required("add", $album); + + switch ($this->input->post("type")) { + case "album": + return $this->_create_album($album); + + case "photo": + return $this->_create_photo($album); + + default: + access::forbidden(); + } + } + + private function _create_album($album) { + access::required("view", $album); + access::required("add", $album); + + $form = album::get_add_form($album); + if ($form->validate()) { + $new_album = album::create( + $album, + $this->input->post("name"), + $this->input->post("title", $this->input->post("name")), + $this->input->post("description"), + user::active()->id); + + log::success("content", "Created an album", + html::anchor("albums/$new_album->id", "view album")); + message::success(t("Created album %album_title", + array("album_title" => html::purify($new_album->title)))); print json_encode( array("result" => "success", -- cgit v1.2.3 From 02409d3b99fe7601cf5ed03d07b03112f2fe0c38 Mon Sep 17 00:00:00 2001 From: Chad Kieffer Date: Wed, 2 Sep 2009 22:35:54 -0600 Subject: Fix bg images in tables bug in webkit and ie. #718 --- modules/gallery/views/admin_maintenance.html.php | 8 ++-- themes/admin_default/css/screen.css | 47 ++++++++++++------------ 2 files changed, 27 insertions(+), 28 deletions(-) diff --git a/modules/gallery/views/admin_maintenance.html.php b/modules/gallery/views/admin_maintenance.html.php index 4bca8653..ce693d73 100644 --- a/modules/gallery/views/admin_maintenance.html.php +++ b/modules/gallery/views/admin_maintenance.html.php @@ -7,7 +7,7 @@

                - +
                - "> + severity) ?>"> @@ -69,7 +69,7 @@ - "> + state == "stalled" ? "gWarning" : "" ?>"> @@ -142,7 +142,7 @@ - "> + state == "success" ? "gSuccess" : "gError" ?>"> diff --git a/themes/admin_default/css/screen.css b/themes/admin_default/css/screen.css index 24328133..c81db58d 100644 --- a/themes/admin_default/css/screen.css +++ b/themes/admin_default/css/screen.css @@ -356,48 +356,47 @@ li.gError select { .gInfo, .gSuccess, .gWarning { - background-position: .4em 50%; - background-repeat: no-repeat; padding: .4em .5em .4em 30px; } -.gError { - background-color: #f6cbca; - background-image: url('../images/ico-error.png'); +.gError, tr.gError td.gError { + background: #f6cbca url('../images/ico-error.png') no-repeat .4em 50%; } .gInfo { - background-color: #e8e8e8; - background-image: url('../images/ico-info.png'); + background: #e8e8e8 url('../images/ico-info.png') no-repeat .4em 50%; } .gSuccess { - background-color: #d9efc2; - background-image: url('../images/ico-success.png'); + background: #d9efc2 url('../images/ico-success.png') no-repeat .4em 50%; } -.gWarning { - background-color: #fcf9ce; - background-image: url('../images/ico-warning.png'); +.gWarning, tr.gWarning td.gWarning { + background: #fcf9ce url('../images/ico-warning.png') no-repeat .4em 50%; +} + +.gPager .gInfo, +tr.gError, +tr.gInfo, +tr.gSuccess, +tr.gWarning { + background: none; } -table .gError { - background-color: #f6cbca !important; +.gInfo td.gInfo { + background-color: transparent; } -table .gWarning { - background-color: #fcf9ce !important; +.gSuccess td.gSuccess { + background-color: transparent; } -.gPager .gInfo, -form .gError, -table .gInfo, -table .gSuccess { - background-color: transparent !important; +.gError td { + background-color: #f6cbca; } -.gPager .gInfo { - background-image: none !important; +.gWarning td { + background-color: #fcf9ce; } /* Inline layout (forms, lists) ~~~~~~~~~~ */ @@ -643,7 +642,7 @@ li.gGroup { li.gGroup h4 { background-color: #eee; - border-bottom: 1px dashed ccc; + border-bottom: 1px dashed #ccc; padding: .5em 0 .5em .5em; } li.gGroup .gButtonLink { -- cgit v1.2.3 From 640d84aba46f4dcd813d7c9ade320f665c1958c0 Mon Sep 17 00:00:00 2001 From: Chad Kieffer Date: Wed, 2 Sep 2009 23:20:45 -0600 Subject: Noticed that loading.gif kept showing up in my logs. Probably not maintainable, but updated jquery.autocomplete css to use the default theme's equivalent. --- lib/jquery.autocomplete.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/jquery.autocomplete.css b/lib/jquery.autocomplete.css index 4d50cf43..cdf26f56 100644 --- a/lib/jquery.autocomplete.css +++ b/lib/jquery.autocomplete.css @@ -36,7 +36,7 @@ } .ac_loading { - background: white url('indicator.gif') right center no-repeat; + background: white url('../themes/default/images/loading-sm.gif') right center no-repeat; } .ac_odd { -- cgit v1.2.3 From 33bcf11e2714f727f16136a1c09926cd5b6c8212 Mon Sep 17 00:00:00 2001 From: Tim Almdal Date: Thu, 3 Sep 2009 01:05:03 -0700 Subject: Change the Html_Helper and SafeString tests to change the expeced results based on whether HtmlPurifier module is installed or not --- modules/gallery/tests/Html_Helper_Test.php | 5 +++-- modules/gallery/tests/SafeString_Test.php | 4 +++- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/modules/gallery/tests/Html_Helper_Test.php b/modules/gallery/tests/Html_Helper_Test.php index bfce6dcf..8f665e0c 100644 --- a/modules/gallery/tests/Html_Helper_Test.php +++ b/modules/gallery/tests/Html_Helper_Test.php @@ -27,8 +27,9 @@ class Html_Helper_Test extends Unit_Test_Case { public function purify_test() { $safe_string = html::purify("hello

                world

                "); - $this->assert_equal("hello

                world

                ", - $safe_string); + $expected = + module::is_active("htmlpurifier") ? "hello

                world

                " : "hello <p >world</p>"; + $this->assert_equal($expected, $safe_string->unescaped()); $this->assert_true($safe_string instanceof SafeString); } diff --git a/modules/gallery/tests/SafeString_Test.php b/modules/gallery/tests/SafeString_Test.php index 0895b7dd..37a1865f 100644 --- a/modules/gallery/tests/SafeString_Test.php +++ b/modules/gallery/tests/SafeString_Test.php @@ -91,7 +91,9 @@ class SafeString_Test extends Unit_Test_Case { public function purify_test() { $safe_string = SafeString::purify("hello

                world

                "); - $this->assert_equal("hello

                world

                ", $safe_string); + $expected = + module::is_active("htmlpurifier") ? "hello

                world

                " : "hello <p >world</p>"; + $this->assert_equal($expected, $safe_string->unescaped()); } public function of_fluid_api_test() { -- cgit v1.2.3 From 41e3773417a78949f44f463b28c41d55413c850b Mon Sep 17 00:00:00 2001 From: Tim Almdal Date: Thu, 3 Sep 2009 01:07:02 -0700 Subject: fix the expected return value of album controller --- modules/gallery/tests/Albums_Controller_Test.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/gallery/tests/Albums_Controller_Test.php b/modules/gallery/tests/Albums_Controller_Test.php index 7674e85f..d65946c7 100644 --- a/modules/gallery/tests/Albums_Controller_Test.php +++ b/modules/gallery/tests/Albums_Controller_Test.php @@ -52,7 +52,7 @@ class Albums_Controller_Test extends Unit_Test_Case { ob_end_clean(); $this->assert_equal( - json_encode(array("result" => "success", "location" => "http://./index.php/test")), + json_encode(array("result" => "success")), $results); $this->assert_equal("new title", $this->_album->title); $this->assert_equal("new description", $this->_album->description); -- cgit v1.2.3 From dcdd44109b13a2cd2b29884edb6090e970178f32 Mon Sep 17 00:00:00 2001 From: Tim Almdal Date: Thu, 3 Sep 2009 01:11:28 -0700 Subject: fix the expected return value of photos controller --- modules/gallery/tests/Photos_Controller_Test.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/modules/gallery/tests/Photos_Controller_Test.php b/modules/gallery/tests/Photos_Controller_Test.php index 5c4802c2..ac5ecdfd 100644 --- a/modules/gallery/tests/Photos_Controller_Test.php +++ b/modules/gallery/tests/Photos_Controller_Test.php @@ -50,8 +50,7 @@ class Photos_Controller_Test extends Unit_Test_Case { ob_end_clean(); $this->assert_equal( - json_encode(array("result" => "success", - "location" => "http://./index.php/test.jpeg")), + json_encode(array("result" => "success")), $results); $this->assert_equal("new title", $this->_photo->title); $this->assert_equal("new description", $this->_photo->description); -- cgit v1.2.3 From 8f6a120b52360475859c361514500e46698f0e74 Mon Sep 17 00:00:00 2001 From: Andy Staudacher Date: Thu, 3 Sep 2009 08:39:44 -0700 Subject: Ensure that purify isn't applied twice for an already purified SafeString --- modules/gallery/libraries/SafeString.php | 6 +++++- modules/gallery/tests/SafeString_Test.php | 10 +++++++++- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/modules/gallery/libraries/SafeString.php b/modules/gallery/libraries/SafeString.php index 800647fa..e6f54add 100644 --- a/modules/gallery/libraries/SafeString.php +++ b/modules/gallery/libraries/SafeString.php @@ -51,7 +51,11 @@ class SafeString_Core { */ static function purify($string) { if ($string instanceof SafeString) { - $string = $string->unescaped(); + if ($string->_is_purified_html) { + return $string; + } else { + $string = $string->unescaped(); + } } $safe_string = self::of_safe_html(self::_purify_for_html($string)); $safe_string->_is_purified_html = true; diff --git a/modules/gallery/tests/SafeString_Test.php b/modules/gallery/tests/SafeString_Test.php index 37a1865f..57ac87b9 100644 --- a/modules/gallery/tests/SafeString_Test.php +++ b/modules/gallery/tests/SafeString_Test.php @@ -93,7 +93,15 @@ class SafeString_Test extends Unit_Test_Case { $safe_string = SafeString::purify("hello

                world

                "); $expected = module::is_active("htmlpurifier") ? "hello

                world

                " : "hello <p >world</p>"; - $this->assert_equal($expected, $safe_string->unescaped()); + $this->assert_equal($expected, $safe_string); + } + + public function purify_twice_test() { + $safe_string = SafeString::purify("hello

                world

                "); + $safe_string_2 = SafeString::purify($safe_string); + $expected = + module::is_active("htmlpurifier") ? "hello

                world

                " : "hello <p >world</p>"; + $this->assert_equal($expected, $safe_string_2); } public function of_fluid_api_test() { -- cgit v1.2.3 From e2d5944e56f7e7433e7f1bda290ba779df447c3c Mon Sep 17 00:00:00 2001 From: Andy Staudacher Date: Thu, 3 Sep 2009 08:49:14 -0700 Subject: Minor performance improvement: Reduce module var cache lookups in SafeString. --- modules/gallery/libraries/SafeString.php | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/modules/gallery/libraries/SafeString.php b/modules/gallery/libraries/SafeString.php index e6f54add..93905572 100644 --- a/modules/gallery/libraries/SafeString.php +++ b/modules/gallery/libraries/SafeString.php @@ -158,8 +158,8 @@ class SafeString_Core { // Purifies the string, removing any potentially malicious or unsafe HTML / JavaScript. private static function _purify_for_html($dirty_html) { - if (module::is_active("htmlpurifier")) { - if (empty(self::$_purifier)) { + if (null === self::$_purifier) { + if (module::is_active("htmlpurifier")) { require_once(MODPATH . "htmlpurifier/lib/HTMLPurifier/HTMLPurifier.auto.php"); $config = HTMLPurifier_Config::createDefault(); foreach (Kohana::config('purifier') as $category => $key_value) { @@ -168,7 +168,11 @@ class SafeString_Core { } } self::$_purifier = new HTMLPurifier($config); + } else { + self::$_purifier = false; } + } + if (self::$_purifier) { return self::$_purifier->purify($dirty_html); } else { return self::_escape_for_html($dirty_html); -- cgit v1.2.3 From 8972d5f05ce4f37061bdd4dd2c8a1a19c1235611 Mon Sep 17 00:00:00 2001 From: Bharat Mediratta Date: Thu, 3 Sep 2009 10:20:54 -0700 Subject: Move the loading images into lib/images and adjust everything to point at them, including jquery.autocomplete.css so that we don't have stuff from lib that points into a theme directory. They were common images anyway. Incidentally, rename sm/lg to small/large. --- lib/images/loading-large.gif | Bin 0 -> 8238 bytes lib/images/loading-small.gif | Bin 0 -> 673 bytes lib/jquery.autocomplete.css | 10 +++++----- themes/admin_default/css/screen.css | 6 +++--- themes/admin_default/images/loading-lg.gif | Bin 8238 -> 0 bytes themes/admin_default/images/loading-sm.gif | Bin 673 -> 0 bytes themes/default/css/screen.css | 6 +++--- themes/default/images/loading-lg.gif | Bin 8238 -> 0 bytes themes/default/images/loading-sm.gif | Bin 673 -> 0 bytes 9 files changed, 11 insertions(+), 11 deletions(-) create mode 100644 lib/images/loading-large.gif create mode 100644 lib/images/loading-small.gif delete mode 100644 themes/admin_default/images/loading-lg.gif delete mode 100644 themes/admin_default/images/loading-sm.gif delete mode 100644 themes/default/images/loading-lg.gif delete mode 100644 themes/default/images/loading-sm.gif diff --git a/lib/images/loading-large.gif b/lib/images/loading-large.gif new file mode 100644 index 00000000..cc70a7a8 Binary files /dev/null and b/lib/images/loading-large.gif differ diff --git a/lib/images/loading-small.gif b/lib/images/loading-small.gif new file mode 100644 index 00000000..d0bce154 Binary files /dev/null and b/lib/images/loading-small.gif differ diff --git a/lib/jquery.autocomplete.css b/lib/jquery.autocomplete.css index cdf26f56..00cd1c9b 100644 --- a/lib/jquery.autocomplete.css +++ b/lib/jquery.autocomplete.css @@ -20,15 +20,15 @@ padding: 2px 5px; cursor: default; display: block; - /* - if width will be 100% horizontal scrollbar will apear + /* + if width will be 100% horizontal scrollbar will apear when scroll mode will be used */ /*width: 100%;*/ font: menu; font-size: 12px; - /* - it is very important, if line-height not setted or setted + /* + it is very important, if line-height not setted or setted in relative units scroll will be broken in firefox */ line-height: 16px; @@ -36,7 +36,7 @@ } .ac_loading { - background: white url('../themes/default/images/loading-sm.gif') right center no-repeat; + background: white url('images/loading-small.gif') right center no-repeat; } .ac_odd { diff --git a/themes/admin_default/css/screen.css b/themes/admin_default/css/screen.css index c81db58d..4f802039 100644 --- a/themes/admin_default/css/screen.css +++ b/themes/admin_default/css/screen.css @@ -768,17 +768,17 @@ li.gDefaultGroup h4, li.gDefaultGroup .gUser { /* Ajax loading indicator ~~~~~~~~~~~~~~~~ */ .gLoadingLarge { - background: #e8e8e8 url('../images/loading-lg.gif') no-repeat center center; + background: #e8e8e8 url('../../../lib/images/loading-arge.gif') no-repeat center center; font-size: 0; } .gDialogLoadingLarge { - background: url('../images/loading-lg.gif') no-repeat center center !important; + background: url('../../../lib/images/loading-large.gif') no-repeat center center !important; font-size: 0; } .gLoadingSmall { - background: #e8e8e8 url('../images/loading-sm.gif') no-repeat center center; + background: #e8e8e8 url('../../../lib/images/loading-small.gif') no-repeat center center; font-size: 0; } diff --git a/themes/admin_default/images/loading-lg.gif b/themes/admin_default/images/loading-lg.gif deleted file mode 100644 index cc70a7a8..00000000 Binary files a/themes/admin_default/images/loading-lg.gif and /dev/null differ diff --git a/themes/admin_default/images/loading-sm.gif b/themes/admin_default/images/loading-sm.gif deleted file mode 100644 index d0bce154..00000000 Binary files a/themes/admin_default/images/loading-sm.gif and /dev/null differ diff --git a/themes/default/css/screen.css b/themes/default/css/screen.css index 96be8996..fd85d696 100644 --- a/themes/default/css/screen.css +++ b/themes/default/css/screen.css @@ -819,17 +819,17 @@ form .gError, /* Ajax loading indicator ~~~~~~~~~~~~~~~~ */ .gLoadingLarge { - background: #e8e8e8 url('../images/loading-lg.gif') no-repeat center center; + background: #e8e8e8 url('../../../lib/images/loading-large.gif') no-repeat center center; font-size: 0; } .gDialogLoadingLarge { - background: url('../images/loading-lg.gif') no-repeat center center !important; + background: url('../../../lib/images/loading-large.gif') no-repeat center center !important; font-size: 0; } .gLoadingSmall { - background: #e8e8e8 url('../images/loading-sm.gif') no-repeat center center; + background: #e8e8e8 url('../../../lib/images/loading-small.gif') no-repeat center center; font-size: 0; } diff --git a/themes/default/images/loading-lg.gif b/themes/default/images/loading-lg.gif deleted file mode 100644 index cc70a7a8..00000000 Binary files a/themes/default/images/loading-lg.gif and /dev/null differ diff --git a/themes/default/images/loading-sm.gif b/themes/default/images/loading-sm.gif deleted file mode 100644 index d0bce154..00000000 Binary files a/themes/default/images/loading-sm.gif and /dev/null differ -- cgit v1.2.3 From 46f1276886e845a522392cbf8c1dddf43ee1d111 Mon Sep 17 00:00:00 2001 From: Bharat Mediratta Date: Thu, 3 Sep 2009 10:39:38 -0700 Subject: Remove extraneous changes to the CSS so that it's just the ones that we need. They'll be documented in our vendor repo. --- lib/jquery.autocomplete.css | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/jquery.autocomplete.css b/lib/jquery.autocomplete.css index 00cd1c9b..ca425822 100644 --- a/lib/jquery.autocomplete.css +++ b/lib/jquery.autocomplete.css @@ -3,8 +3,8 @@ border: 1px solid black; background-color: white; overflow: hidden; - text-align: left; z-index: 99999; + text-align: left; } .ac_results ul { @@ -20,15 +20,15 @@ padding: 2px 5px; cursor: default; display: block; - /* - if width will be 100% horizontal scrollbar will apear + /* + if width will be 100% horizontal scrollbar will apear when scroll mode will be used */ /*width: 100%;*/ font: menu; font-size: 12px; - /* - it is very important, if line-height not setted or setted + /* + it is very important, if line-height not setted or setted in relative units scroll will be broken in firefox */ line-height: 16px; -- cgit v1.2.3 From 53e2df01ebc26337fab13da2c38e6f2555a673d0 Mon Sep 17 00:00:00 2001 From: Bharat Mediratta Date: Thu, 3 Sep 2009 11:21:45 -0700 Subject: html::purify an item title. --- themes/default/views/album.html.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/themes/default/views/album.html.php b/themes/default/views/album.html.php index 8bc81a31..01f7be50 100644 --- a/themes/default/views/album.html.php +++ b/themes/default/views/album.html.php @@ -20,7 +20,7 @@ thumb_bottom($child) ?> context_menu($child, "#gItemId-{$child->id} .gThumbnail") ?> -

                title) ?>

                +

                title) ?>

                -- cgit v1.2.3 From 82dd468002d5d21a5c8c391d6fce543b3df43de1 Mon Sep 17 00:00:00 2001 From: Bharat Mediratta Date: Thu, 3 Sep 2009 11:25:02 -0700 Subject: Refactor interaction with the purifier module so that the API is cleaner and we don't need to know about the module innards. Move the config file over there too. --- modules/gallery/config/purifier.php | 27 --------------------------- modules/gallery/libraries/SafeString.php | 28 ++++++++-------------------- 2 files changed, 8 insertions(+), 47 deletions(-) delete mode 100644 modules/gallery/config/purifier.php diff --git a/modules/gallery/config/purifier.php b/modules/gallery/config/purifier.php deleted file mode 100644 index 30de9dc5..00000000 --- a/modules/gallery/config/purifier.php +++ /dev/null @@ -1,27 +0,0 @@ - TMPPATH -); - -$config["Attr"] = array( - "EnableID" => true -); diff --git a/modules/gallery/libraries/SafeString.php b/modules/gallery/libraries/SafeString.php index 93905572..3328fed5 100644 --- a/modules/gallery/libraries/SafeString.php +++ b/modules/gallery/libraries/SafeString.php @@ -26,8 +26,6 @@ class SafeString_Core { protected $_is_safe_html = false; protected $_is_purified_html = false; - private static $_purifier = null; - /** Constructor */ function __construct($string) { if ($string instanceof SafeString) { @@ -151,29 +149,19 @@ class SafeString_Core { return $this->_raw_string; } - // Escapes special HTML chars ("<", ">", "&", etc.) to HTML entities. + /** + * Escape special HTML chars ("<", ">", "&", etc.) to HTML entities. + */ private static function _escape_for_html($dirty_html) { return html::specialchars($dirty_html); } - // Purifies the string, removing any potentially malicious or unsafe HTML / JavaScript. + /** + * Purify the string, removing any potentially malicious or unsafe HTML / JavaScript. + */ private static function _purify_for_html($dirty_html) { - if (null === self::$_purifier) { - if (module::is_active("htmlpurifier")) { - require_once(MODPATH . "htmlpurifier/lib/HTMLPurifier/HTMLPurifier.auto.php"); - $config = HTMLPurifier_Config::createDefault(); - foreach (Kohana::config('purifier') as $category => $key_value) { - foreach ($key_value as $key => $value) { - $config->set("$category.$key", $value); - } - } - self::$_purifier = new HTMLPurifier($config); - } else { - self::$_purifier = false; - } - } - if (self::$_purifier) { - return self::$_purifier->purify($dirty_html); + if (method_exists("purifier", "purify")) { + return purifier::purify($dirty_html); } else { return self::_escape_for_html($dirty_html); } -- cgit v1.2.3 From 1dca0b9d6be5a96e79e3de776e231e21ed824589 Mon Sep 17 00:00:00 2001 From: Bharat Mediratta Date: Thu, 3 Sep 2009 11:28:42 -0700 Subject: Fix test for new purifier API. --- modules/gallery/tests/Html_Helper_Test.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/modules/gallery/tests/Html_Helper_Test.php b/modules/gallery/tests/Html_Helper_Test.php index 8f665e0c..1662b866 100644 --- a/modules/gallery/tests/Html_Helper_Test.php +++ b/modules/gallery/tests/Html_Helper_Test.php @@ -27,8 +27,9 @@ class Html_Helper_Test extends Unit_Test_Case { public function purify_test() { $safe_string = html::purify("hello

                world

                "); - $expected = - module::is_active("htmlpurifier") ? "hello

                world

                " : "hello <p >world</p>"; + $expected = method_exists("purifier", "purify") + ? "hello

                world

                " + : "hello <p >world</p>"; $this->assert_equal($expected, $safe_string->unescaped()); $this->assert_true($safe_string instanceof SafeString); } -- cgit v1.2.3 From 1405e8ed9e2003d1b06853bae4ce3413de1910ce Mon Sep 17 00:00:00 2001 From: Bharat Mediratta Date: Thu, 3 Sep 2009 11:29:57 -0700 Subject: Fix tests for new purifier API. --- modules/gallery/tests/SafeString_Test.php | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/modules/gallery/tests/SafeString_Test.php b/modules/gallery/tests/SafeString_Test.php index 57ac87b9..fdab5c58 100644 --- a/modules/gallery/tests/SafeString_Test.php +++ b/modules/gallery/tests/SafeString_Test.php @@ -91,16 +91,18 @@ class SafeString_Test extends Unit_Test_Case { public function purify_test() { $safe_string = SafeString::purify("hello

                world

                "); - $expected = - module::is_active("htmlpurifier") ? "hello

                world

                " : "hello <p >world</p>"; + $expected = method_exists("purifier", "purify") + ? "hello

                world

                " + : "hello <p >world</p>"; $this->assert_equal($expected, $safe_string); } public function purify_twice_test() { $safe_string = SafeString::purify("hello

                world

                "); $safe_string_2 = SafeString::purify($safe_string); - $expected = - module::is_active("htmlpurifier") ? "hello

                world

                " : "hello <p >world</p>"; + $expected = method_exists("purifier", "purify") + ? "hello

                world

                " + : "hello <p >world</p>"; $this->assert_equal($expected, $safe_string_2); } -- cgit v1.2.3 From 1ffb5b24dff439b4a3e9e7f2df3af1a0f8e9e5a0 Mon Sep 17 00:00:00 2001 From: Bharat Mediratta Date: Thu, 3 Sep 2009 11:34:02 -0700 Subject: Checkpoint. --- modules/gallery/tests/xss_data.txt | 40 ++++++++++++++++++-------------------- 1 file changed, 19 insertions(+), 21 deletions(-) diff --git a/modules/gallery/tests/xss_data.txt b/modules/gallery/tests/xss_data.txt index 7e536e90..00eba901 100644 --- a/modules/gallery/tests/xss_data.txt +++ b/modules/gallery/tests/xss_data.txt @@ -71,19 +71,19 @@ modules/gallery/views/admin_languages.html.php 28 DIRTY form:: modules/gallery/views/admin_languages.html.php 29 DIRTY $display_name modules/gallery/views/admin_languages.html.php 31 DIRTY form::radio("default_locale",$code,($default_locale==$code),((isset($installed_locales[$code]))?'':'disabled="disabled"')) modules/gallery/views/admin_languages.html.php 102 DIRTY $share_translations_form -modules/gallery/views/admin_maintenance.html.php 24 DIRTY_ATTR log::severity_class($task->severity) modules/gallery/views/admin_maintenance.html.php 24 DIRTY_ATTR ($i%2==0)?"gOddRow":"gEvenRow" +modules/gallery/views/admin_maintenance.html.php 24 DIRTY_ATTR log::severity_class($task->severity) modules/gallery/views/admin_maintenance.html.php 25 DIRTY_ATTR log::severity_class($task->severity) modules/gallery/views/admin_maintenance.html.php 26 DIRTY $task->name modules/gallery/views/admin_maintenance.html.php 29 DIRTY $task->description -modules/gallery/views/admin_maintenance.html.php 72 DIRTY_ATTR $task->state=="stalled"?"gWarning":"" modules/gallery/views/admin_maintenance.html.php 72 DIRTY_ATTR ($i%2==0)?"gOddRow":"gEvenRow" +modules/gallery/views/admin_maintenance.html.php 72 DIRTY_ATTR $task->state=="stalled"?"gWarning":"" modules/gallery/views/admin_maintenance.html.php 73 DIRTY_ATTR $task->state=="stalled"?"gWarning":"" modules/gallery/views/admin_maintenance.html.php 74 DIRTY gallery::date_time($task->updated) modules/gallery/views/admin_maintenance.html.php 77 DIRTY $task->name modules/gallery/views/admin_maintenance.html.php 92 DIRTY $task->status -modules/gallery/views/admin_maintenance.html.php 145 DIRTY_ATTR $task->state=="success"?"gSuccess":"gError" modules/gallery/views/admin_maintenance.html.php 145 DIRTY_ATTR ($i%2==0)?"gOddRow":"gEvenRow" +modules/gallery/views/admin_maintenance.html.php 145 DIRTY_ATTR $task->state=="success"?"gSuccess":"gError" modules/gallery/views/admin_maintenance.html.php 146 DIRTY_ATTR $task->state=="success"?"gSuccess":"gError" modules/gallery/views/admin_maintenance.html.php 147 DIRTY gallery::date_time($task->updated) modules/gallery/views/admin_maintenance.html.php 150 DIRTY $task->name @@ -142,11 +142,11 @@ modules/gallery/views/movieplayer.html.php 7 DIRTY_JS url::a modules/gallery/views/movieplayer.html.php 13 DIRTY_JS url::abs_file("lib/flowplayer.h264streaming.swf") 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 41 DIRTY_ATTR $parent->id -modules/gallery/views/permissions_browse.html.php 42 DIRTY_JS $parent->id -modules/gallery/views/permissions_browse.html.php 47 DIRTY_ATTR $item->id -modules/gallery/views/permissions_browse.html.php 48 DIRTY_JS $item->id -modules/gallery/views/permissions_browse.html.php 55 DIRTY $form +modules/gallery/views/permissions_browse.html.php 42 DIRTY_ATTR $parent->id +modules/gallery/views/permissions_browse.html.php 43 DIRTY_JS $parent->id +modules/gallery/views/permissions_browse.html.php 48 DIRTY_ATTR $item->id +modules/gallery/views/permissions_browse.html.php 49 DIRTY_JS $item->id +modules/gallery/views/permissions_browse.html.php 56 DIRTY $form modules/gallery/views/permissions_form.html.php 24 DIRTY_JS $lock->id modules/gallery/views/permissions_form.html.php 32 DIRTY_JS $group->id modules/gallery/views/permissions_form.html.php 32 DIRTY_JS $permission->id @@ -280,17 +280,17 @@ modules/user/views/login_ajax.html.php 37 DIRTY $form modules/watermark/views/admin_watermarks.html.php 19 DIRTY_ATTR $width modules/watermark/views/admin_watermarks.html.php 19 DIRTY_ATTR $height modules/watermark/views/admin_watermarks.html.php 19 DIRTY_ATTR $url -themes/admin_default/views/admin.html.php 16 DIRTY_JS $theme->url() -themes/admin_default/views/admin.html.php 34 DIRTY $theme->admin_head() -themes/admin_default/views/admin.html.php 38 DIRTY $theme->admin_page_top() -themes/admin_default/views/admin.html.php 46 DIRTY $theme->admin_header_top() -themes/admin_default/views/admin.html.php 55 DIRTY $theme->admin_menu() -themes/admin_default/views/admin.html.php 57 DIRTY $theme->admin_header_bottom() -themes/admin_default/views/admin.html.php 64 DIRTY $content -themes/admin_default/views/admin.html.php 70 DIRTY $sidebar -themes/admin_default/views/admin.html.php 75 DIRTY $theme->admin_footer() -themes/admin_default/views/admin.html.php 77 DIRTY $theme->admin_credits() -themes/admin_default/views/admin.html.php 81 DIRTY $theme->admin_page_bottom() +themes/admin_default/views/admin.html.php 15 DIRTY_JS $theme->url() +themes/admin_default/views/admin.html.php 32 DIRTY $theme->admin_head() +themes/admin_default/views/admin.html.php 36 DIRTY $theme->admin_page_top() +themes/admin_default/views/admin.html.php 44 DIRTY $theme->admin_header_top() +themes/admin_default/views/admin.html.php 53 DIRTY $theme->admin_menu() +themes/admin_default/views/admin.html.php 55 DIRTY $theme->admin_header_bottom() +themes/admin_default/views/admin.html.php 62 DIRTY $content +themes/admin_default/views/admin.html.php 68 DIRTY $sidebar +themes/admin_default/views/admin.html.php 73 DIRTY $theme->admin_footer() +themes/admin_default/views/admin.html.php 75 DIRTY $theme->admin_credits() +themes/admin_default/views/admin.html.php 79 DIRTY $theme->admin_page_bottom() themes/admin_default/views/block.html.php 2 DIRTY $id themes/admin_default/views/block.html.php 2 DIRTY_ATTR $css_id themes/admin_default/views/block.html.php 10 DIRTY $title @@ -319,13 +319,11 @@ themes/default/views/movie.html.php 8 DIRTY_JS $previ themes/default/views/movie.html.php 18 DIRTY_JS $next_item->url() themes/default/views/movie.html.php 28 DIRTY $item->movie_img(array("class"=>"gMovie","id"=>"gMovieId-{$item->id}")) themes/default/views/page.html.php 9 DIRTY $page_title -themes/default/views/page.html.php 26 DIRTY_JS $theme->url() themes/default/views/page.html.php 32 DIRTY_JS $theme->url() themes/default/views/page.html.php 41 DIRTY $new_width themes/default/views/page.html.php 42 DIRTY $new_height themes/default/views/page.html.php 43 DIRTY $thumb_proportion themes/default/views/page.html.php 82 DIRTY $header_text -themes/default/views/page.html.php 85 DIRTY_ATTR $theme->url() themes/default/views/page.html.php 112 DIRTY $content themes/default/views/page.html.php 118 DIRTY newView("sidebar.html") themes/default/views/page.html.php 125 DIRTY $footer_text -- cgit v1.2.3 From c453c0ef8239bc79e484dd3feb9e275e942e9d48 Mon Sep 17 00:00:00 2001 From: Andy Staudacher Date: Fri, 4 Sep 2009 10:11:42 -0700 Subject: Simplifying SafeString a bit: From a XSS HTML security point of view, treat clean() and purify() the same. No longer run a safe HTML string through the HTML purifier (since it's already marked as safe). This also addresses the issue of calling purify() when no purifier is installed. In that case, we'd run clean() on a clean string (double HTML encoding). If this approach doesn't work out, we can still modify the fallback code of purify() to check if the string is already clean before calling clean() instead of purify(). --- modules/gallery/libraries/SafeString.php | 11 ++--------- modules/gallery/tests/SafeString_Test.php | 6 ++++++ 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/modules/gallery/libraries/SafeString.php b/modules/gallery/libraries/SafeString.php index 3328fed5..ba3a8ffd 100644 --- a/modules/gallery/libraries/SafeString.php +++ b/modules/gallery/libraries/SafeString.php @@ -24,13 +24,11 @@ class SafeString_Core { private $_raw_string; protected $_is_safe_html = false; - protected $_is_purified_html = false; /** Constructor */ function __construct($string) { if ($string instanceof SafeString) { $this->_is_safe_html = $string->_is_safe_html; - $this->_is_purified_html = $string->_is_purified_html; $string = $string->unescaped(); } $this->_raw_string = (string) $string; @@ -49,14 +47,13 @@ class SafeString_Core { */ static function purify($string) { if ($string instanceof SafeString) { - if ($string->_is_purified_html) { + if ($string->_is_safe_html) { return $string; } else { $string = $string->unescaped(); } } $safe_string = self::of_safe_html(self::_purify_for_html($string)); - $safe_string->_is_purified_html = true; return $safe_string; } @@ -135,11 +132,7 @@ class SafeString_Core { * @return the string escaped for use in HTML. */ function purified_html() { - if ($this->_is_purified_html) { - return $this; - } else { - return self::purify($this); - } + return self::purify($this); } /** diff --git a/modules/gallery/tests/SafeString_Test.php b/modules/gallery/tests/SafeString_Test.php index fdab5c58..2c07d934 100644 --- a/modules/gallery/tests/SafeString_Test.php +++ b/modules/gallery/tests/SafeString_Test.php @@ -106,6 +106,12 @@ class SafeString_Test extends Unit_Test_Case { $this->assert_equal($expected, $safe_string_2); } + public function purify_safe_html_test() { + $safe_string = SafeString::of_safe_html("hello

                world

                "); + $actual = SafeString::purify($safe_string); + $this->assert_equal("hello

                world

                ", $actual); + } + public function of_fluid_api_test() { $escaped_string = SafeString::of("Foo's bar")->for_js(); $this->assert_equal('"Foo\'s bar"', $escaped_string); -- cgit v1.2.3 From 001623c755777846a468255d4396d30b253dcdfb Mon Sep 17 00:00:00 2001 From: Andy Staudacher Date: Fri, 4 Sep 2009 11:06:20 -0700 Subject: Add new locale preferences: Adding per session (cookie) locale preferences and check the browser's / OS' locale preferences. Ticket 582. --- modules/gallery/helpers/locales.php | 85 +++++++++++++++++++++++++++++++++++++ modules/user/helpers/user.php | 18 ++++++++ modules/user/helpers/user_event.php | 24 ++++++++--- modules/user/helpers/user_theme.php | 24 +++++++++++ 4 files changed, 145 insertions(+), 6 deletions(-) diff --git a/modules/gallery/helpers/locales.php b/modules/gallery/helpers/locales.php index 3762b97b..1320c155 100644 --- a/modules/gallery/helpers/locales.php +++ b/modules/gallery/helpers/locales.php @@ -23,6 +23,7 @@ */ class locales_Core { private static $locales; + private static $language_subtag_to_locale; /** * Return the list of available locales. @@ -105,6 +106,16 @@ class locales_Core { $l["zh_TW"] = "繁體中文"; // Chinese (TW) asort($l, SORT_LOCALE_STRING); self::$locales = $l; + + // Language subtag to (default) locale mapping + foreach ($l as $locale => $name) { + list ($language) = explode("_", $locale . "_"); + // The first one mentioned is the default + if (!isset($d[$language])) { + $d[$language] = $locale; + } + } + self::$language_subtag_to_locale = $d; } static function display_name($locale=null) { @@ -121,4 +132,78 @@ class locales_Core { list ($language, $territory) = explode('_', $locale . "_"); return in_array($language, array("he", "fa", "ar")); } + + /** + * Returns the best match comparing the HTTP accept-language header + * with the installed locales. + */ + static function locale_from_http_request() { + $http_accept_language = Input::instance()->server("HTTP_ACCEPT_LANGUAGE"); + if ($http_accept_language) { + // Parse the HTTP header and build a preference list + // Example value: "de,en-us;q=0.7,en-uk,fr-fr;q=0.2" + $locale_preferences = array(); + foreach (explode(",", $http_accept_language) as $code) { + list ($requested_locale, $qvalue) = explode(";", $code . ";"); + $requested_locale = trim($requested_locale); + $qvalue = trim($qvalue); + if (preg_match("/^([a-z]{2,3})(?:[_-]([a-zA-Z]{2}))?/", $requested_locale, $matches)) { + $requested_locale = strtolower($matches[1]); + if (!empty($matches[2])) { + $requested_locale .= "_" . strtoupper($matches[2]); + } + $requested_locale = trim(str_replace("-", "_", $requested_locale)); + if (!strlen($qvalue)) { + // If not specified, default to 1. + $qvalue = 1; + } else { + // qvalue is expected to be something like "q=0.7" + list ($ignored, $qvalue) = explode("=", $qvalue . "=="); + $qvalue = floatval($qvalue); + } + $locale_preferences[] = array($requested_locale, $qvalue); + } + } + + // Compare and score requested locales with installed ones + $matched_locales = array(); + foreach ($locale_preferences as $requested_value) { + $scored_locale_match = self::_locale_match_score($requested_value); + if ($scored_locale_match) { + $scored_locales[] = $scored_locale_match; + } + } + + usort($matched_locales, array("locales", "_compare_locale_by_qvalue")); + + $best_match = array_shift($scored_locales); + if ($best_match) { + return $best_match[0]; + } + } + + return null; + } + + static function _compare_locale_by_qvalue($a, $b) { + $a = $a[1]; + $b = $b[1]; + if ($a == $b) { + return 0; + } + return $a < $b ? 1 : -1; + } + + private static function _locale_match_score($requested_locale_and_qvalue) { + list ($requested_locale, $qvalue) = $requested_locale_and_qvalue; + $installed = self::installed(); + if (isset($installed[$requested_locale])) { + return $requested_locale_and_qvalue; + } + list ($language) = explode("_", $requested_locale . "_"); + if (isset(self::$language_subtag_to_locale[$language])) { + return array(self::$language_subtag_to_locale[$language], $qvalue * 0.66); + } + return null; + } } \ No newline at end of file diff --git a/modules/user/helpers/user.php b/modules/user/helpers/user.php index 40acc2ec..b9162b92 100644 --- a/modules/user/helpers/user.php +++ b/modules/user/helpers/user.php @@ -87,6 +87,9 @@ class user_Core { private static function _add_locale_dropdown(&$form, $user=null) { $locales = locales::installed(); + foreach ($locales as $locale => $display_name) { + $locales[$locale] = SafeString::of_safe_html($display_name); + } if (count($locales) > 1) { // Put "none" at the first position in the array $locales = array_merge(array("" => t("« none »")), $locales); @@ -336,4 +339,19 @@ class user_Core { } return $salt . md5($salt . $password); } + + static function cookie_locale() { + $cookie_data = Input::instance()->cookie("g_locale"); + $locale = null; + if ($cookie_data) { + if (preg_match("/^([a-z]{2,3}(?:_[A-Z]{2})?)$/", trim($cookie_data), $matches)) { + $requested_locale = $matches[1]; + $installed_locales = locales::installed(); + if (isset($installed_locales[$requested_locale])) { + $locale = $requested_locale; + } + } + } + return $locale; + } } \ No newline at end of file diff --git a/modules/user/helpers/user_event.php b/modules/user/helpers/user_event.php index 4bde224b..ede4e515 100644 --- a/modules/user/helpers/user_event.php +++ b/modules/user/helpers/user_event.php @@ -23,12 +23,7 @@ class user_event_Core { */ static function gallery_ready() { user::load_user(); - - $locale = user::active()->locale; - if (!empty($locale)) { - // TODO(andy_st): Check session data as well. - I18n::instance()->locale($locale); - } + self::set_request_locale(); } static function admin_menu($menu, $theme) { @@ -38,4 +33,21 @@ class user_event_Core { ->label(t("Users/Groups")) ->url(url::site("admin/users"))); } + + static function set_request_locale() { + // 1. Check the session specific preference (cookie) + $locale = user::cookie_locale(); + // 2. Check the user's preference + if (!$locale) { + $locale = user::active()->locale; + } + // 3. Check the browser's / OS' preference + if (!$locale) { + $locale = locales::locale_from_http_request(); + } + // If we have any preference, override the site's default locale + if ($locale) { + I18n::instance()->locale($locale); + } + } } diff --git a/modules/user/helpers/user_theme.php b/modules/user/helpers/user_theme.php index 8de2d248..5b973ef3 100644 --- a/modules/user/helpers/user_theme.php +++ b/modules/user/helpers/user_theme.php @@ -18,6 +18,14 @@ * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ class user_theme_Core { + static function head($theme) { + if (count(locales::installed())) { + // Needed by the languages block + $theme->script("jquery.cookie.js"); + } + return ""; + } + static function header_top($theme) { if ($theme->page_type != "login") { $view = new View("login.html"); @@ -25,4 +33,20 @@ class user_theme_Core { return $view->render(); } } + + static function sidebar_blocks($theme) { + $locales = locales::installed(); + foreach ($locales as $locale => $display_name) { + $locales[$locale] = SafeString::of_safe_html($display_name); + } + if (count($locales) > 1) { + $block = new Block(); + $block->css_id = "gUserLanguageBlock"; + $block->title = t("Select Language Preference"); + $block->content = new View("user_languages_block.html"); + $block->content->installed_locales = array_merge(array("" => t("« none »")), $locales); + $block->content->selected = (string) user::cookie_locale(); + return $block; + } + } } -- cgit v1.2.3 From 75e99c9ea33fa5723dec9a2f5250e8bb38755718 Mon Sep 17 00:00:00 2001 From: Andy Staudacher Date: Fri, 4 Sep 2009 11:17:11 -0700 Subject: When changing user preferences, reset the session based locale preferences. --- modules/user/controllers/users.php | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/modules/user/controllers/users.php b/modules/user/controllers/users.php index 0bf2e81d..4ad704f0 100644 --- a/modules/user/controllers/users.php +++ b/modules/user/controllers/users.php @@ -36,7 +36,12 @@ class Users_Controller extends REST_Controller { $user->url = $form->edit_user->url->value; if ($form->edit_user->locale) { $desired_locale = $form->edit_user->locale->value; - $user->locale = $desired_locale == "none" ? null : $desired_locale; + $new_locale = $desired_locale == "none" ? null : $desired_locale; + if ($new_locale != $user->locale) { + // Delete the session based locale preference + setcookie("g_locale", "", time() - 24 * 3600, "/"); + } + $user->locale = $new_locale; } $user->save(); module::event("user_edit_form_completed", $user, $form); -- cgit v1.2.3 From f63766556a701c173f578caea58597ea7febb865 Mon Sep 17 00:00:00 2001 From: Andy Staudacher Date: Fri, 4 Sep 2009 11:20:02 -0700 Subject: XSS test golden data file update --- modules/gallery/tests/xss_data.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/modules/gallery/tests/xss_data.txt b/modules/gallery/tests/xss_data.txt index 00eba901..a1a708df 100644 --- a/modules/gallery/tests/xss_data.txt +++ b/modules/gallery/tests/xss_data.txt @@ -277,6 +277,7 @@ modules/user/views/admin_users_group.html.php 22 DIRTY_JS $user- modules/user/views/admin_users_group.html.php 22 DIRTY_JS $group->id modules/user/views/login_ajax.html.php 6 DIRTY_JS url::site("password/reset") modules/user/views/login_ajax.html.php 37 DIRTY $form +modules/user/views/user_languages_block.html.php 2 DIRTY form::dropdown("gSelectSessionLocale",$installed_locales,$selected) modules/watermark/views/admin_watermarks.html.php 19 DIRTY_ATTR $width modules/watermark/views/admin_watermarks.html.php 19 DIRTY_ATTR $height modules/watermark/views/admin_watermarks.html.php 19 DIRTY_ATTR $url -- cgit v1.2.3 From ca1947a1ce9d3f70df88c6a5f6260923c5f035c1 Mon Sep 17 00:00:00 2001 From: Bharat Mediratta Date: Fri, 4 Sep 2009 20:15:21 -0700 Subject: Updated upstream to r4554 --- system/helpers/url.php | 9 ++++++--- system/libraries/Session.php | 9 +++++++-- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/system/helpers/url.php b/system/helpers/url.php index f3d0ec8b..56f6db4b 100644 --- a/system/helpers/url.php +++ b/system/helpers/url.php @@ -2,7 +2,7 @@ /** * URL helper class. * - * $Id: url.php 4029 2009-03-03 12:39:32Z Shadowhand $ + * $Id: url.php 4479 2009-07-23 04:51:22Z ixmatus $ * * @package Core * @author Kohana Team @@ -15,11 +15,14 @@ class url_Core { * Fetches the current URI. * * @param boolean include the query string + * @param boolean include the suffix * @return string */ - public static function current($qs = FALSE) + public static function current($qs = FALSE, $suffix = FALSE) { - return ($qs === TRUE) ? Router::$complete_uri : Router::$current_uri; + $uri = ($qs === TRUE) ? Router::$complete_uri : Router::$current_uri; + + return ($suffix === TRUE) ? $uri.Kohana::config('core.url_suffix') : $uri; } /** diff --git a/system/libraries/Session.php b/system/libraries/Session.php index 670ee6a6..51acce00 100644 --- a/system/libraries/Session.php +++ b/system/libraries/Session.php @@ -2,7 +2,7 @@ /** * Session library. * - * $Id: Session.php 4433 2009-07-01 03:44:20Z kiall $ + * $Id: Session.php 4493 2009-07-27 20:05:41Z ixmatus $ * * @package Core * @author Kohana Team @@ -43,11 +43,16 @@ class Session_Core { return Session::$instance; } + + /** + * Be sure to block the use of __clone. + */ + private function __clone(){} /** * On first session instance creation, sets up the driver and creates session. */ - public function __construct() + protected function __construct() { $this->input = Input::instance(); -- cgit v1.2.3 From 49de9bba68dd466dadd3c4df3d5024b3820568ff Mon Sep 17 00:00:00 2001 From: Bharat Mediratta Date: Fri, 4 Sep 2009 20:19:15 -0700 Subject: Add @todo to replace locales::locale_from_http_request() request::accepts_language() when we upgrade to Kohana 2.4 --- modules/gallery/helpers/locales.php | 1 + 1 file changed, 1 insertion(+) diff --git a/modules/gallery/helpers/locales.php b/modules/gallery/helpers/locales.php index 1320c155..04fa8954 100644 --- a/modules/gallery/helpers/locales.php +++ b/modules/gallery/helpers/locales.php @@ -136,6 +136,7 @@ class locales_Core { /** * Returns the best match comparing the HTTP accept-language header * with the installed locales. + * @todo replace this with request::accepts_language() when we upgrade to Kohana 2.4 */ static function locale_from_http_request() { $http_accept_language = Input::instance()->server("HTTP_ACCEPT_LANGUAGE"); -- cgit v1.2.3 From bca7080debcdf67bc0b35e67f2697e56414b5159 Mon Sep 17 00:00:00 2001 From: Bharat Mediratta Date: Fri, 4 Sep 2009 20:23:00 -0700 Subject: Fix typo: loading-arge.gif -> loading-large.gif --- themes/admin_default/css/screen.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/themes/admin_default/css/screen.css b/themes/admin_default/css/screen.css index 4f802039..33cc6733 100644 --- a/themes/admin_default/css/screen.css +++ b/themes/admin_default/css/screen.css @@ -768,7 +768,7 @@ li.gDefaultGroup h4, li.gDefaultGroup .gUser { /* Ajax loading indicator ~~~~~~~~~~~~~~~~ */ .gLoadingLarge { - background: #e8e8e8 url('../../../lib/images/loading-arge.gif') no-repeat center center; + background: #e8e8e8 url('../../../lib/images/loading-large.gif') no-repeat center center; font-size: 0; } -- cgit v1.2.3 From a25640f9b26c75e14109f07fcc4863adc300f062 Mon Sep 17 00:00:00 2001 From: Bharat Mediratta Date: Fri, 4 Sep 2009 20:28:46 -0700 Subject: Shorten the name in the block so that it doesn't wrap. Use « and » in the << none >> text. --- modules/user/helpers/user_theme.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/modules/user/helpers/user_theme.php b/modules/user/helpers/user_theme.php index 5b973ef3..184a2bc9 100644 --- a/modules/user/helpers/user_theme.php +++ b/modules/user/helpers/user_theme.php @@ -42,9 +42,10 @@ class user_theme_Core { if (count($locales) > 1) { $block = new Block(); $block->css_id = "gUserLanguageBlock"; - $block->title = t("Select Language Preference"); + $block->title = t("Language Preference"); $block->content = new View("user_languages_block.html"); - $block->content->installed_locales = array_merge(array("" => t("« none »")), $locales); + $block->content->installed_locales = + array_merge(array("" => t("« none »")), $locales); $block->content->selected = (string) user::cookie_locale(); return $block; } -- cgit v1.2.3 From add134cc75214c3852566ae27e5eb7b35c59c53e Mon Sep 17 00:00:00 2001 From: Bharat Mediratta Date: Fri, 4 Sep 2009 20:29:12 -0700 Subject: placeholder for a missing view --- modules/user/views/user_languages_block.html.php | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 modules/user/views/user_languages_block.html.php diff --git a/modules/user/views/user_languages_block.html.php b/modules/user/views/user_languages_block.html.php new file mode 100644 index 00000000..c422f55c --- /dev/null +++ b/modules/user/views/user_languages_block.html.php @@ -0,0 +1,2 @@ + + -- cgit v1.2.3 From ab7323d17b3c3e445fb51d7b4330e89b4e16aaa9 Mon Sep 17 00:00:00 2001 From: Bharat Mediratta Date: Fri, 4 Sep 2009 21:27:23 -0700 Subject: Fix the url in the call to get subsequent entries to have the right url, and to be json. Fixes #719, which I introduced in my refactor. --- modules/organize/views/organize_thumb_grid.html.php | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/modules/organize/views/organize_thumb_grid.html.php b/modules/organize/views/organize_thumb_grid.html.php index 929d9ec3..af7136fc 100644 --- a/modules/organize/views/organize_thumb_grid.html.php +++ b/modules/organize/views/organize_thumb_grid.html.php @@ -11,12 +11,13 @@ children_count() > $offset): ?> -- cgit v1.2.3 From 9fbdcf3efd37e2c6bf67b197b8c93f8790a79cbe Mon Sep 17 00:00:00 2001 From: Bharat Mediratta Date: Sat, 5 Sep 2009 13:39:30 -0700 Subject: Change the module installer so that you don't need to provide your own install() function if all you're going to do is to set the version of the module from module.info into the database. This means that for some simple modules, you don't need an install.php file at all. --- modules/akismet/helpers/akismet_installer.php | 4 ---- modules/gallery/helpers/module.php | 9 ++++++++ .../image_block/helpers/image_block_installer.php | 24 ---------------------- modules/info/helpers/info_installer.php | 24 ---------------------- modules/organize/helpers/organize_installer.php | 24 ---------------------- modules/recaptcha/helpers/recaptcha_installer.php | 4 ---- modules/rss/helpers/rss_installer.php | 24 ---------------------- modules/slideshow/helpers/slideshow_installer.php | 4 ---- 8 files changed, 9 insertions(+), 108 deletions(-) delete mode 100644 modules/image_block/helpers/image_block_installer.php delete mode 100644 modules/info/helpers/info_installer.php delete mode 100644 modules/organize/helpers/organize_installer.php delete mode 100644 modules/rss/helpers/rss_installer.php diff --git a/modules/akismet/helpers/akismet_installer.php b/modules/akismet/helpers/akismet_installer.php index 5d8c0e07..b891fc7b 100644 --- a/modules/akismet/helpers/akismet_installer.php +++ b/modules/akismet/helpers/akismet_installer.php @@ -18,10 +18,6 @@ * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ class akismet_installer { - static function install() { - module::set_version("akismet", 1); - } - static function activate() { akismet::check_config(); } diff --git a/modules/gallery/helpers/module.php b/modules/gallery/helpers/module.php index 03d538a9..a3088c38 100644 --- a/modules/gallery/helpers/module.php +++ b/modules/gallery/helpers/module.php @@ -119,6 +119,8 @@ class module_Core { $installer_class = "{$module_name}_installer"; if (method_exists($installer_class, "install")) { call_user_func_array(array($installer_class, "install"), array()); + } else { + module::set_version($module_name, 1); } module::load_modules(); @@ -145,6 +147,13 @@ class module_Core { $installer_class = "{$module_name}_installer"; if (method_exists($installer_class, "upgrade")) { call_user_func_array(array($installer_class, "upgrade"), array($version_before)); + } else { + $available = module::available(); + if (isset($available->$module_name->code_version)) { + module::set_version($module_name, $available->$module_name->code_version); + } else { + throw new Exception("@todo UNKNOWN_MODULE"); + } } module::load_modules(); diff --git a/modules/image_block/helpers/image_block_installer.php b/modules/image_block/helpers/image_block_installer.php deleted file mode 100644 index 7ea6a229..00000000 --- a/modules/image_block/helpers/image_block_installer.php +++ /dev/null @@ -1,24 +0,0 @@ - Date: Sat, 5 Sep 2009 17:39:49 -0700 Subject: Add missing view for language selection --- modules/user/views/user_languages_block.html.php | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/modules/user/views/user_languages_block.html.php b/modules/user/views/user_languages_block.html.php index c422f55c..df145bc0 100644 --- a/modules/user/views/user_languages_block.html.php +++ b/modules/user/views/user_languages_block.html.php @@ -1,2 +1,19 @@ - + + + -- cgit v1.2.3 From beb232a1cc6f081b432f32a72bddadcaf3f90df4 Mon Sep 17 00:00:00 2001 From: Andy Staudacher Date: Sat, 5 Sep 2009 17:43:47 -0700 Subject: Revert previous edit. Prefer « none » (sweet, nice Unicode characters) instead of HTML entities. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- modules/user/helpers/user_theme.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/user/helpers/user_theme.php b/modules/user/helpers/user_theme.php index 184a2bc9..098d87fd 100644 --- a/modules/user/helpers/user_theme.php +++ b/modules/user/helpers/user_theme.php @@ -45,7 +45,7 @@ class user_theme_Core { $block->title = t("Language Preference"); $block->content = new View("user_languages_block.html"); $block->content->installed_locales = - array_merge(array("" => t("« none »")), $locales); + array_merge(array("" => t("« none »")), $locales); $block->content->selected = (string) user::cookie_locale(); return $block; } -- cgit v1.2.3 From b01596c0f08f00e5fc2d1019b3905fe5fd76a223 Mon Sep 17 00:00:00 2001 From: Andy Staudacher Date: Sat, 5 Sep 2009 18:19:13 -0700 Subject: Update XSS test golden data file. --- modules/gallery/tests/xss_data.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/gallery/tests/xss_data.txt b/modules/gallery/tests/xss_data.txt index a1a708df..ffd69eb1 100644 --- a/modules/gallery/tests/xss_data.txt +++ b/modules/gallery/tests/xss_data.txt @@ -200,7 +200,7 @@ modules/organize/views/organize_thumb_grid.html.php 3 DIRTY_ATTR $chi modules/organize/views/organize_thumb_grid.html.php 4 DIRTY_ATTR $child->id modules/organize/views/organize_thumb_grid.html.php 5 DIRTY_ATTR $child->is_album()?"gAlbum":"gPhoto" modules/organize/views/organize_thumb_grid.html.php 6 DIRTY $child->thumb_img(array("class"=>"gThumbnail","ref"=>$child->id),90,true) -modules/organize/views/organize_thumb_grid.html.php 14 DIRTY_JS url::site("organize/content/$album->id/".($offset+25)) +modules/organize/views/organize_thumb_grid.html.php 14 DIRTY_JS url::site("organize/album/$album->id/".($offset+25)) modules/organize/views/organize_tree.html.php 2 DIRTY_ATTR access::can("edit",$album)?"":"gViewOnly" modules/organize/views/organize_tree.html.php 3 DIRTY_ATTR $album->id modules/organize/views/organize_tree.html.php 6 DIRTY_ATTR $selected&&$album->id==$selected->id?"selected":"" -- cgit v1.2.3 From b3d0cb5a4c88c42e29e67f3b3eb4e91151802164 Mon Sep 17 00:00:00 2001 From: Andy Staudacher Date: Sat, 5 Sep 2009 18:55:44 -0700 Subject: Bugfixes for locales::locale_from_http_request(), and adding tests. (And the tests should illustrate that kohana 2.4's API doesn't quite fit our purpose of simply getting the best match between the accepted (client) and the installed (g3) locales.) --- modules/gallery/helpers/locales.php | 10 +++- modules/gallery/tests/Locales_Helper_Test.php | 86 +++++++++++++++++++++++++++ 2 files changed, 93 insertions(+), 3 deletions(-) create mode 100644 modules/gallery/tests/Locales_Helper_Test.php diff --git a/modules/gallery/helpers/locales.php b/modules/gallery/helpers/locales.php index 04fa8954..16dda2d7 100644 --- a/modules/gallery/helpers/locales.php +++ b/modules/gallery/helpers/locales.php @@ -56,6 +56,9 @@ class locales_Core { : array_merge($locales, array($default)); module::set_var("gallery", "installed_locales", join("|", $locales)); + + // Clear the cache + self::$locales = null; } // @todo Might want to add a localizable language name as well. @@ -167,7 +170,7 @@ class locales_Core { } // Compare and score requested locales with installed ones - $matched_locales = array(); + $scored_locales = array(); foreach ($locale_preferences as $requested_value) { $scored_locale_match = self::_locale_match_score($requested_value); if ($scored_locale_match) { @@ -175,7 +178,7 @@ class locales_Core { } } - usort($matched_locales, array("locales", "_compare_locale_by_qvalue")); + usort($scored_locales, array("locales", "_compare_locale_by_qvalue")); $best_match = array_shift($scored_locales); if ($best_match) { @@ -202,7 +205,8 @@ class locales_Core { return $requested_locale_and_qvalue; } list ($language) = explode("_", $requested_locale . "_"); - if (isset(self::$language_subtag_to_locale[$language])) { + if (isset(self::$language_subtag_to_locale[$language]) && + isset($installed[self::$language_subtag_to_locale[$language]])) { return array(self::$language_subtag_to_locale[$language], $qvalue * 0.66); } return null; diff --git a/modules/gallery/tests/Locales_Helper_Test.php b/modules/gallery/tests/Locales_Helper_Test.php new file mode 100644 index 00000000..85b8e206 --- /dev/null +++ b/modules/gallery/tests/Locales_Helper_Test.php @@ -0,0 +1,86 @@ +assert_equal("de_DE", $locale); + } + + public function locale_from_http_request_fallback_test() { + $_SERVER["HTTP_ACCEPT_LANGUAGE"] = "de"; + $locale = locales::locale_from_http_request(); + $this->assert_equal("de_DE", $locale); + } + + public function locale_from_http_request_by_qvalue_test() { + $_SERVER["HTTP_ACCEPT_LANGUAGE"] = "de-de;q=0.8,fr-fr;q=0.9"; + $locale = locales::locale_from_http_request(); + $this->assert_equal("fr_FR", $locale); + } + + public function locale_from_http_request_default_qvalue_test() { + $_SERVER["HTTP_ACCEPT_LANGUAGE"] = "de-de;q=0.8,it-it,fr-fr;q=0.9"; + $locale = locales::locale_from_http_request(); + $this->assert_equal("it_IT", $locale); + } + + public function locale_from_http_request_lang_fallback_qvalue_adjustment_test() { + $_SERVER["HTTP_ACCEPT_LANGUAGE"] = ",fr-fr;q=0.4,de-ch;q=0.8"; + $locale = locales::locale_from_http_request(); + $this->assert_equal("de_DE", $locale); + } + + public function locale_from_http_request_best_match_vs_installed_test() { + locales::update_installed(array("no_NO", "pt_PT", "ja_JP")); + $_SERVER["HTTP_ACCEPT_LANGUAGE"] = "en,en-us,ja_JP;q=0.7,no-fr;q=0.9"; + $locale = locales::locale_from_http_request(); + $this->assert_equal("ja_JP", $locale); + } + + public function locale_from_http_request_best_match_vs_installed_2_test() { + locales::update_installed(array("no_NO", "pt_PT", "ja_JP")); + $_SERVER["HTTP_ACCEPT_LANGUAGE"] = "en,en-us,ja_JP;q=0.5,no-fr;q=0.9"; + $locale = locales::locale_from_http_request(); + $this->assert_equal("no_NO", $locale); + } + + public function locale_from_http_request_no_match_vs_installed_test() { + locales::update_installed(array("no_NO", "pt_PT", "ja_JP")); + $_SERVER["HTTP_ACCEPT_LANGUAGE"] = "en,en-us,de"; + $locale = locales::locale_from_http_request(); + $this->assert_equal(null, $locale); + } +} \ No newline at end of file -- cgit v1.2.3 From d8f5b0f5a30adb97d48fa49999c6ec7407666c44 Mon Sep 17 00:00:00 2001 From: Bharat Mediratta Date: Sat, 5 Sep 2009 21:14:25 -0700 Subject: Change click() to change() so that we immediately update the UI when the user picks a new option. --- modules/user/views/user_languages_block.html.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/user/views/user_languages_block.html.php b/modules/user/views/user_languages_block.html.php index df145bc0..b5ae674c 100644 --- a/modules/user/views/user_languages_block.html.php +++ b/modules/user/views/user_languages_block.html.php @@ -1,7 +1,7 @@ -

                - -

                - Gallery website has news and information about the Gallery project and community.", array("url" => "http://gallery.menalto.com")) ?> -

                - -

                - documentation site or you can ask for help in the forums!", array("codex_url" => "http://codex.gallery2.org/Main_Page", "forum_url" => "http://gallery.menalto.com/forum")) ?> - diff --git a/modules/gallery/views/after_install_loader.html.php b/modules/gallery/views/after_install_loader.html.php deleted file mode 100644 index c2e3e1d9..00000000 --- a/modules/gallery/views/after_install_loader.html.php +++ /dev/null @@ -1,7 +0,0 @@ - -for_html_attr() ?>" - href=""/> - diff --git a/modules/gallery/views/welcome_message.html.php b/modules/gallery/views/welcome_message.html.php new file mode 100644 index 00000000..5515c3dc --- /dev/null +++ b/modules/gallery/views/welcome_message.html.php @@ -0,0 +1,36 @@ + +

                +

                + +

                + +

                +

                + +

                +

                + +

                + %user_name account. You should change your password to something that you'll remember.", array("user_name" => $user->name)) ?> +

                + +

                + id}") ?>" + title="for_html_attr() ?>" + id="gAfterInstallChangePasswordLink" + class="gButtonLink ui-state-default ui-corners-all"> + + + +

                + +

                + Gallery website has news and information about the Gallery project and community.", array("url" => "http://gallery.menalto.com")) ?> +

                + +

                + documentation site or you can ask for help in the forums!", array("codex_url" => "http://codex.gallery2.org/Main_Page", "forum_url" => "http://gallery.menalto.com/forum")) ?> +

                +
                diff --git a/modules/gallery/views/welcome_message_loader.html.php b/modules/gallery/views/welcome_message_loader.html.php new file mode 100644 index 00000000..2c6bffca --- /dev/null +++ b/modules/gallery/views/welcome_message_loader.html.php @@ -0,0 +1,7 @@ + +for_html_attr() ?>" + href=""/> + diff --git a/themes/default/css/screen.css b/themes/default/css/screen.css index fec618e6..d4c23155 100644 --- a/themes/default/css/screen.css +++ b/themes/default/css/screen.css @@ -773,6 +773,10 @@ form .gError, text-decoration: underline; } +#gWelcomeMessage p { + padding-bottom: 1em; +} + /* Pagination ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ .gPager { -- cgit v1.2.3 From 190d7aaa55b4f55ea3d93fb8a3d4650d7e1fc85c Mon Sep 17 00:00:00 2001 From: Bharat Mediratta Date: Thu, 10 Sep 2009 21:12:15 -0700 Subject: Remove debug code. --- modules/gallery/helpers/gallery_theme.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/gallery/helpers/gallery_theme.php b/modules/gallery/helpers/gallery_theme.php index 8c97f124..20dfeb04 100644 --- a/modules/gallery/helpers/gallery_theme.php +++ b/modules/gallery/helpers/gallery_theme.php @@ -70,7 +70,7 @@ class gallery_theme_Core { return L10n_Client_Controller::l10n_form(); } - if (true || $session->get("after_install")) { + if ($session->get("after_install")) { $session->delete("after_install"); return new View("welcome_message_loader.html"); } -- cgit v1.2.3 From 3dd40bf97c45c4cb2cc40e9f20796a799f4e1255 Mon Sep 17 00:00:00 2001 From: Bharat Mediratta Date: Thu, 10 Sep 2009 21:22:07 -0700 Subject: Trim the input line to get rid of carriage returns on Windows. Fixes ticket #740. Thanks to jankoprowski! --- installer/installer.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/installer/installer.php b/installer/installer.php index 4480e35e..7a417634 100644 --- a/installer/installer.php +++ b/installer/installer.php @@ -60,7 +60,7 @@ class installer { $prefix = $config["prefix"]; $buf = null; foreach (file(DOCROOT . "installer/install.sql") as $line) { - $buf .= $line; + $buf .= trim($line); if (preg_match("/;$/", $buf)) { if (!mysql_query(self::prepend_prefix($prefix, $buf))) { return false; -- cgit v1.2.3 From 25ea6085b78423ee651dc21b639c5f10f59dcaf0 Mon Sep 17 00:00:00 2001 From: Tim Almdal Date: Thu, 10 Sep 2009 21:26:07 -0700 Subject: Reset the margins when the mouse is over a thumbnail when dragging. When the border is displayed then adjust the margin to account for the border. Just hidding the border causes things to move. --- modules/organize/js/organize.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/modules/organize/js/organize.js b/modules/organize/js/organize.js index 0aeb4f7c..c30f89e0 100644 --- a/modules/organize/js/organize.js +++ b/modules/organize/js/organize.js @@ -122,12 +122,12 @@ mouse_move_handler: function(event) { if ($(".gDragHelper").length) { - $(".gOrganizeMicroThumbGridCell").css("borderStyle", "hidden"); + $(".gOrganizeMicroThumbGridCell").css({borderStyle: "hidden", margin: "4px"}); $(".currentDropTarget").removeClass("currentDropTarget"); var borderStyle = event.pageX < $(this).offset().left + $(this).width() / 2 ? - "borderLeftStyle" : "borderRightStyle"; + {borderLeftStyle: "solid", marginLeft: "2px"} : {borderRightStyle: "solid", marginRight: "2px"}; $(this).addClass("currentDropTarget") - .css(borderStyle, "solid"); + .css(borderStyle); } }, -- cgit v1.2.3 From 7fddd2aced1821f977323fc75f2954f2b240ae37 Mon Sep 17 00:00:00 2001 From: Bharat Mediratta Date: Thu, 10 Sep 2009 21:31:50 -0700 Subject: Use abs_url() inside url::redirect() calls so that we don't just wind up tacking onto the base url. --- modules/gallery/controllers/albums.php | 8 ++++---- modules/gallery/controllers/items.php | 2 +- modules/gallery/controllers/l10n_client.php | 10 +++++----- modules/gallery/controllers/welcome_message.php | 2 +- modules/notification/controllers/notification.php | 2 +- modules/user/controllers/login.php | 2 +- modules/user/controllers/logout.php | 2 +- modules/user/controllers/password.php | 2 +- 8 files changed, 15 insertions(+), 15 deletions(-) diff --git a/modules/gallery/controllers/albums.php b/modules/gallery/controllers/albums.php index 8455d95c..183c26d0 100644 --- a/modules/gallery/controllers/albums.php +++ b/modules/gallery/controllers/albums.php @@ -42,9 +42,9 @@ class Albums_Controller extends Items_Controller { $index = $album->get_position($show); $page = ceil($index / $page_size); if ($page == 1) { - url::redirect($album->url()); + url::redirect($album->abs_url()); } else { - url::redirect($album->url("page=$page")); + url::redirect($album->abs_url("page=$page")); } } @@ -55,9 +55,9 @@ class Albums_Controller extends Items_Controller { // Make sure that the page references a valid offset if ($page < 1) { - url::redirect($album->url()); + url::redirect($album->abs_url()); } else if ($page > $max_pages) { - url::redirect($album->url("page=$max_pages")); + url::redirect($album->abs_url("page=$max_pages")); } $template = new Theme_View("page.html", "album"); diff --git a/modules/gallery/controllers/items.php b/modules/gallery/controllers/items.php index 13891726..7f60f2b7 100644 --- a/modules/gallery/controllers/items.php +++ b/modules/gallery/controllers/items.php @@ -25,6 +25,6 @@ class Items_Controller extends REST_Controller { // differently. We could also just delegate here, but it feels more appropriate // to have a single canonical resource mapping. access::required("view", $item); - return url::redirect($item->url(array(), true)); + return url::redirect($item->abs_url()); } } diff --git a/modules/gallery/controllers/l10n_client.php b/modules/gallery/controllers/l10n_client.php index 16d39024..6e19310b 100644 --- a/modules/gallery/controllers/l10n_client.php +++ b/modules/gallery/controllers/l10n_client.php @@ -90,14 +90,14 @@ class L10n_Client_Controller extends Controller { } $session = Session::instance(); - $l10n_mode = $session->get("l10n_mode", false); + $l10n_mode = $session->get("l10n_mode", false); $session->set("l10n_mode", !$l10n_mode); $redirect_url = "admin/languages"; - if (!$l10n_mode) { - $redirect_url .= "#l10n-client"; - } - + if (!$l10n_mode) { + $redirect_url .= "#l10n-client"; + } + url::redirect($redirect_url); } diff --git a/modules/gallery/controllers/welcome_message.php b/modules/gallery/controllers/welcome_message.php index a4b690e3..8fd1e0a0 100644 --- a/modules/gallery/controllers/welcome_message.php +++ b/modules/gallery/controllers/welcome_message.php @@ -20,7 +20,7 @@ class Welcome_Message_Controller extends Controller { public function index() { if (!user::active()->admin) { - url::redirect(item::root()->url()); + url::redirect(item::root()->abs_url()); } $v = new View("welcome_message.html"); diff --git a/modules/notification/controllers/notification.php b/modules/notification/controllers/notification.php index 5745de5d..d502b9fe 100644 --- a/modules/notification/controllers/notification.php +++ b/modules/notification/controllers/notification.php @@ -31,6 +31,6 @@ class Notification_Controller extends Controller { notification::add_watch($item); message::success(sprintf(t("You are now watching %s"), html::purify($item->title))); } - url::redirect($item->url(array(), true)); + url::redirect($item->abs_url()); } } diff --git a/modules/user/controllers/login.php b/modules/user/controllers/login.php index dcac0723..8bee7db5 100644 --- a/modules/user/controllers/login.php +++ b/modules/user/controllers/login.php @@ -48,7 +48,7 @@ class Login_Controller extends Controller { list ($valid, $form) = $this->_auth("login/auth_html"); if ($valid) { - url::redirect(item::root()->url()); + url::redirect(item::root()->abs_url()); } else { print $form; } diff --git a/modules/user/controllers/logout.php b/modules/user/controllers/logout.php index 3bf274a6..45d397ad 100644 --- a/modules/user/controllers/logout.php +++ b/modules/user/controllers/logout.php @@ -31,7 +31,7 @@ class Logout_Controller extends Controller { // Don't use url::redirect() because it'll call url::site() and munge the continue url. header("Location: $continue_url"); } else { - url::redirect(item::root()->url()); + url::redirect(item::root()->abs_url()); } } } diff --git a/modules/user/controllers/password.php b/modules/user/controllers/password.php index 8c18916e..92608dcd 100644 --- a/modules/user/controllers/password.php +++ b/modules/user/controllers/password.php @@ -130,7 +130,7 @@ class Password_Controller extends Controller { $user->hash = null; $user->save(); message::success(t("Password reset successfully")); - url::redirect(item::root()->url()); + url::redirect(item::root()->abs_url()); } else { print $view; } -- cgit v1.2.3 From 882a6d9a5dbf04ac26e046713f47068cd1361b74 Mon Sep 17 00:00:00 2001 From: Bharat Mediratta Date: Thu, 10 Sep 2009 21:33:04 -0700 Subject: Convert a couple of instances of Item_Model::url(array(), true) to Item_Model::abs_url() --- modules/notification/views/item_added.html.php | 4 ++-- modules/notification/views/item_updated.html.php | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/modules/notification/views/item_added.html.php b/modules/notification/views/item_added.html.php index f697fea6..1ea3720d 100644 --- a/modules/notification/views/item_added.html.php +++ b/modules/notification/views/item_added.html.php @@ -13,8 +13,8 @@
                diff --git a/modules/notification/views/item_updated.html.php b/modules/notification/views/item_updated.html.php index ba03540a..9c200964 100644 --- a/modules/notification/views/item_updated.html.php +++ b/modules/notification/views/item_updated.html.php @@ -17,7 +17,7 @@ - + original("description") != $item->description): ?> -- cgit v1.2.3 From af4411a44750b373916b841e01dac8ab434be68c Mon Sep 17 00:00:00 2001 From: Bharat Mediratta Date: Thu, 10 Sep 2009 21:55:36 -0700 Subject: Put the buttons for album/photo dialogs in their own group in the form so that they appear at the end, after any other groups that other modules add. Thanks Glooper! --- modules/gallery/helpers/album.php | 1 + modules/gallery/helpers/photo.php | 1 + 2 files changed, 2 insertions(+) diff --git a/modules/gallery/helpers/album.php b/modules/gallery/helpers/album.php index bae480b7..dfb1e66d 100644 --- a/modules/gallery/helpers/album.php +++ b/modules/gallery/helpers/album.php @@ -152,6 +152,7 @@ class album_Core { module::event("item_edit_form", $parent, $form); + $group = $form->group("buttons")->label(""); $group->hidden("type")->value("album"); $group->submit("")->value(t("Modify")); $form->add_rules_from(ORM::factory("item")); diff --git a/modules/gallery/helpers/photo.php b/modules/gallery/helpers/photo.php index a56c7e3c..3d9fbe69 100644 --- a/modules/gallery/helpers/photo.php +++ b/modules/gallery/helpers/photo.php @@ -178,6 +178,7 @@ class photo_Core { module::event("item_edit_form", $photo, $form); + $group = $form->group("buttons")->label(""); $group->submit("")->value(t("Modify")); $form->add_rules_from(ORM::factory("item")); return $form; -- cgit v1.2.3 From 935a898c02030e3371b6662749979ec7181a3bc1 Mon Sep 17 00:00:00 2001 From: Chad Kieffer Date: Thu, 10 Sep 2009 22:58:37 -0600 Subject: Clear the Upload queue label from the breadcrumbs in the Add Photos dialog. --- themes/default/css/screen.css | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/themes/default/css/screen.css b/themes/default/css/screen.css index d4c23155..b0a0a590 100644 --- a/themes/default/css/screen.css +++ b/themes/default/css/screen.css @@ -1022,6 +1022,11 @@ form .gError, display: inline-block; } +#gAddPhotos span { + clear: both; + display: block; +} + #gAddPhotosCanvas { height: 325px; width: 450px; -- cgit v1.2.3 From e15426abab6017ad13d8a5f30f4b613c6ee193e8 Mon Sep 17 00:00:00 2001 From: Chad Kieffer Date: Thu, 10 Sep 2009 23:18:51 -0600 Subject: Clean up server add dialog a bit. --- themes/default/css/screen.css | 22 +++------------------- 1 file changed, 3 insertions(+), 19 deletions(-) diff --git a/themes/default/css/screen.css b/themes/default/css/screen.css index b0a0a590..b8632285 100644 --- a/themes/default/css/screen.css +++ b/themes/default/css/screen.css @@ -945,13 +945,13 @@ form .gError, /* Server Add */ #gServerAdd button { - float: left; margin-bottom: .5em; } #gServerAddTree { cursor: pointer; padding-left: 4px; + width: 95%; } #gServerAddTree li { @@ -965,32 +965,16 @@ form .gError, #gServerAddTree { border: 1px solid #ccc; - height: 25em; + height: 20em; overflow: auto; margin-bottom: .5em; - padding-top: .5em; - padding-bottom: .5em; + padding: .5em; } #gServerAdd ul ul li { padding-left: 1.2em; } -#gServerAdd .gBreadcrumbs { - font-size: 1em; - padding: 0; - margin: 0; - border-top-width: 0; -} - -#gServerAdd p { - margin: 0; -} - -#gServerAdd .gBreadcrumbs li { - padding: 10px 6px 10px 16px; -} - /* Permissions ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ #gEditPermissionForm { -- cgit v1.2.3 From 35f7f653634f295d5fe9ca1443c5e6d481f860fb Mon Sep 17 00:00:00 2001 From: Chad Kieffer Date: Thu, 10 Sep 2009 23:26:37 -0600 Subject: Fix breadcrumbs in all dialogs rather than piecemeal. --- themes/default/css/screen.css | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/themes/default/css/screen.css b/themes/default/css/screen.css index b8632285..64ecf775 100644 --- a/themes/default/css/screen.css +++ b/themes/default/css/screen.css @@ -702,6 +702,12 @@ form .gError, font-weight: bold; } +#gDialog ul.gBreadcrumbs { + clear: both; + margin-left: 0; + padding-left: 0; +} + #gDialog .gBreadcrumbs li { font-size: .9em; } -- cgit v1.2.3 From 7ec490b6009965920fea35e971b29f11df6e6bff Mon Sep 17 00:00:00 2001 From: Bharat Mediratta Date: Fri, 11 Sep 2009 11:04:35 -0700 Subject: rawurlencode() path components in relative_path_cache and relative_url_cache so that they're safe for browser use. --- modules/gallery/models/item.php | 4 ++-- modules/gallery/tests/Item_Model_Test.php | 10 ++++++++++ 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/modules/gallery/models/item.php b/modules/gallery/models/item.php index da1f6959..a87997c6 100644 --- a/modules/gallery/models/item.php +++ b/modules/gallery/models/item.php @@ -284,8 +284,8 @@ class Item_Model extends ORM_MPTT { ->where("id <>", 1) ->orderby("left_ptr", "ASC") ->get() as $row) { - $names[] = urlencode($row->name); - $slugs[] = urlencode($row->slug); + $names[] = rawurlencode($row->name); + $slugs[] = rawurlencode($row->slug); } $this->relative_path_cache = implode($names, "/"); $this->relative_url_cache = implode($slugs, "/"); diff --git a/modules/gallery/tests/Item_Model_Test.php b/modules/gallery/tests/Item_Model_Test.php index 585e247c..84210e4c 100644 --- a/modules/gallery/tests/Item_Model_Test.php +++ b/modules/gallery/tests/Item_Model_Test.php @@ -150,4 +150,14 @@ class Item_Model_Test extends Unit_Test_Case { $this->assert_same("ORIGINAL_VALUE", $item->original()->title); $this->assert_same("NEW_VALUE", $item->title); } + + public function urls_are_rawurlencoded_test() { + $item = self::_create_random_item(); + $item->slug = "foo bar"; + $item->name = "foo bar.jpg"; + $item->save(); + + $this->assert_equal("foo%20bar", $item->relative_url()); + $this->assert_equal("foo%20bar.jpg", $item->relative_path()); + } } -- cgit v1.2.3 From e1b9565232fac63ce63b29c434211ad9763b13ac Mon Sep 17 00:00:00 2001 From: Bharat Mediratta Date: Fri, 11 Sep 2009 11:16:52 -0700 Subject: Change all booleans to use php_flag instead of php_value. And turn off suhosin.session.encrypt by default. --- .htaccess | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/.htaccess b/.htaccess index 8c2e3793..1d8bcb34 100644 --- a/.htaccess +++ b/.htaccess @@ -1,12 +1,13 @@ - php_value short_open_tag 1 - php_value magic_quotes_gpc 0 - php_value magic_quotes_sybase 0 - php_value magic_quotes_runtime 0 - php_value register_globals 0 - php_value session.auto_start 0 - php_value upload_max_filesize 20M - php_value post_max_size 100M + php_flag short_open_tag On + php_flag magic_quotes_gpc Off + php_flag magic_quotes_sybase Off + php_flag magic_quotes_runtime Off + php_flag register_globals Off + php_flag session.auto_start Off + php_flag suhosin.session.encrypt Off + php_value upload_max_filesize 20M + php_value post_max_size 100M # Try to disable the parts of mod_security that interfere with the Flash uploader -- cgit v1.2.3 From 42454cad5afc7f78b557766f4182299327dee9b1 Mon Sep 17 00:00:00 2001 From: Tim Almdal Date: Sat, 12 Sep 2009 08:50:19 -0700 Subject: Update the jquery-ui.js to use the release version of Selectable --- lib/jquery-ui.js | 969 ++++++++++++++++++------------------------------------- 1 file changed, 320 insertions(+), 649 deletions(-) diff --git a/lib/jquery-ui.js b/lib/jquery-ui.js index 4939d009..c803ea27 100644 --- a/lib/jquery-ui.js +++ b/lib/jquery-ui.js @@ -1,649 +1,320 @@ -/* - * jQuery UI 1.7.2 - * - * Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT (MIT-LICENSE.txt) - * and GPL (GPL-LICENSE.txt) licenses. - * - * http://docs.jquery.com/UI - */ -jQuery.ui||(function(c){var i=c.fn.remove,d=c.browser.mozilla&&(parseFloat(c.browser.version)<1.9);c.ui={version:"1.7.2",plugin:{add:function(k,l,n){var m=c.ui[k].prototype;for(var j in n){m.plugins[j]=m.plugins[j]||[];m.plugins[j].push([l,n[j]])}},call:function(j,l,k){var n=j.plugins[l];if(!n||!j.element[0].parentNode){return}for(var m=0;m0){return true}m[j]=1;l=(m[j]>0);m[j]=0;return l},isOverAxis:function(k,j,l){return(k>j)&&(k<(j+l))},isOver:function(o,k,n,m,j,l){return c.ui.isOverAxis(o,n,j)&&c.ui.isOverAxis(k,m,l)},keyCode:{BACKSPACE:8,CAPS_LOCK:20,COMMA:188,CONTROL:17,DELETE:46,DOWN:40,END:35,ENTER:13,ESCAPE:27,HOME:36,INSERT:45,LEFT:37,NUMPAD_ADD:107,NUMPAD_DECIMAL:110,NUMPAD_DIVIDE:111,NUMPAD_ENTER:108,NUMPAD_MULTIPLY:106,NUMPAD_SUBTRACT:109,PAGE_DOWN:34,PAGE_UP:33,PERIOD:190,RIGHT:39,SHIFT:16,SPACE:32,TAB:9,UP:38}};if(d){var f=c.attr,e=c.fn.removeAttr,h="http://www.w3.org/2005/07/aaa",a=/^aria-/,b=/^wairole:/;c.attr=function(k,j,l){var m=l!==undefined;return(j=="role"?(m?f.call(this,k,j,"wairole:"+l):(f.apply(this,arguments)||"").replace(b,"")):(a.test(j)?(m?k.setAttributeNS(h,j.replace(a,"aaa:"),l):f.call(this,k,j.replace(a,"aaa:"))):f.apply(this,arguments)))};c.fn.removeAttr=function(j){return(a.test(j)?this.each(function(){this.removeAttributeNS(h,j.replace(a,""))}):e.call(this,j))}}c.fn.extend({remove:function(){c("*",this).add(this).each(function(){c(this).triggerHandler("remove")});return i.apply(this,arguments)},enableSelection:function(){return this.attr("unselectable","off").css("MozUserSelect","").unbind("selectstart.ui")},disableSelection:function(){return this.attr("unselectable","on").css("MozUserSelect","none").bind("selectstart.ui",function(){return false})},scrollParent:function(){var j;if((c.browser.msie&&(/(static|relative)/).test(this.css("position")))||(/absolute/).test(this.css("position"))){j=this.parents().filter(function(){return(/(relative|absolute|fixed)/).test(c.curCSS(this,"position",1))&&(/(auto|scroll)/).test(c.curCSS(this,"overflow",1)+c.curCSS(this,"overflow-y",1)+c.curCSS(this,"overflow-x",1))}).eq(0)}else{j=this.parents().filter(function(){return(/(auto|scroll)/).test(c.curCSS(this,"overflow",1)+c.curCSS(this,"overflow-y",1)+c.curCSS(this,"overflow-x",1))}).eq(0)}return(/fixed/).test(this.css("position"))||!j.length?c(document):j}});c.extend(c.expr[":"],{data:function(l,k,j){return !!c.data(l,j[3])},focusable:function(k){var l=k.nodeName.toLowerCase(),j=c.attr(k,"tabindex");return(/input|select|textarea|button|object/.test(l)?!k.disabled:"a"==l||"area"==l?k.href||!isNaN(j):!isNaN(j))&&!c(k)["area"==l?"parents":"closest"](":hidden").length},tabbable:function(k){var j=c.attr(k,"tabindex");return(isNaN(j)||j>=0)&&c(k).is(":focusable")}});function g(m,n,o,l){function k(q){var p=c[m][n][q]||[];return(typeof p=="string"?p.split(/,?\s+/):p)}var j=k("getter");if(l.length==1&&typeof l[0]=="string"){j=j.concat(k("getterSetter"))}return(c.inArray(o,j)!=-1)}c.widget=function(k,j){var l=k.split(".")[0];k=k.split(".")[1];c.fn[k]=function(p){var n=(typeof p=="string"),o=Array.prototype.slice.call(arguments,1);if(n&&p.substring(0,1)=="_"){return this}if(n&&g(l,k,p,o)){var m=c.data(this[0],k);return(m?m[p].apply(m,o):undefined)}return this.each(function(){var q=c.data(this,k);(!q&&!n&&c.data(this,k,new c[l][k](this,p))._init());(q&&n&&c.isFunction(q[p])&&q[p].apply(q,o))})};c[l]=c[l]||{};c[l][k]=function(o,n){var m=this;this.namespace=l;this.widgetName=k;this.widgetEventPrefix=c[l][k].eventPrefix||k;this.widgetBaseClass=l+"-"+k;this.options=c.extend({},c.widget.defaults,c[l][k].defaults,c.metadata&&c.metadata.get(o)[k],n);this.element=c(o).bind("setData."+k,function(q,p,r){if(q.target==o){return m._setData(p,r)}}).bind("getData."+k,function(q,p){if(q.target==o){return m._getData(p)}}).bind("remove",function(){return m.destroy()})};c[l][k].prototype=c.extend({},c.widget.prototype,j);c[l][k].getterSetter="option"};c.widget.prototype={_init:function(){},destroy:function(){this.element.removeData(this.widgetName).removeClass(this.widgetBaseClass+"-disabled "+this.namespace+"-state-disabled").removeAttr("aria-disabled")},option:function(l,m){var k=l,j=this;if(typeof l=="string"){if(m===undefined){return this._getData(l)}k={};k[l]=m}c.each(k,function(n,o){j._setData(n,o)})},_getData:function(j){return this.options[j]},_setData:function(j,k){this.options[j]=k;if(j=="disabled"){this.element[k?"addClass":"removeClass"](this.widgetBaseClass+"-disabled "+this.namespace+"-state-disabled").attr("aria-disabled",k)}},enable:function(){this._setData("disabled",false)},disable:function(){this._setData("disabled",true)},_trigger:function(l,m,n){var p=this.options[l],j=(l==this.widgetEventPrefix?l:this.widgetEventPrefix+l);m=c.Event(m);m.type=j;if(m.originalEvent){for(var k=c.event.props.length,o;k;){o=c.event.props[--k];m[o]=m.originalEvent[o]}}this.element.trigger(m,n);return !(c.isFunction(p)&&p.call(this.element[0],m,n)===false||m.isDefaultPrevented())}};c.widget.defaults={disabled:false};c.ui.mouse={_mouseInit:function(){var j=this;this.element.bind("mousedown."+this.widgetName,function(k){return j._mouseDown(k)}).bind("click."+this.widgetName,function(k){if(j._preventClickEvent){j._preventClickEvent=false;k.stopImmediatePropagation();return false}});if(c.browser.msie){this._mouseUnselectable=this.element.attr("unselectable");this.element.attr("unselectable","on")}this.started=false},_mouseDestroy:function(){this.element.unbind("."+this.widgetName);(c.browser.msie&&this.element.attr("unselectable",this._mouseUnselectable))},_mouseDown:function(l){l.originalEvent=l.originalEvent||{};if(l.originalEvent.mouseHandled){return}(this._mouseStarted&&this._mouseUp(l));this._mouseDownEvent=l;var k=this,m=(l.which==1),j=(typeof this.options.cancel=="string"?c(l.target).parents().add(l.target).filter(this.options.cancel).length:false);if(!m||j||!this._mouseCapture(l)){return true}this.mouseDelayMet=!this.options.delay;if(!this.mouseDelayMet){this._mouseDelayTimer=setTimeout(function(){k.mouseDelayMet=true},this.options.delay)}if(this._mouseDistanceMet(l)&&this._mouseDelayMet(l)){this._mouseStarted=(this._mouseStart(l)!==false);if(!this._mouseStarted){l.preventDefault();return true}}this._mouseMoveDelegate=function(n){return k._mouseMove(n)};this._mouseUpDelegate=function(n){return k._mouseUp(n)};c(document).bind("mousemove."+this.widgetName,this._mouseMoveDelegate).bind("mouseup."+this.widgetName,this._mouseUpDelegate);(c.browser.safari||l.preventDefault());l.originalEvent.mouseHandled=true;return true},_mouseMove:function(j){if(c.browser.msie&&!j.button){return this._mouseUp(j)}if(this._mouseStarted){this._mouseDrag(j);return j.preventDefault()}if(this._mouseDistanceMet(j)&&this._mouseDelayMet(j)){this._mouseStarted=(this._mouseStart(this._mouseDownEvent,j)!==false);(this._mouseStarted?this._mouseDrag(j):this._mouseUp(j))}return !this._mouseStarted},_mouseUp:function(j){c(document).unbind("mousemove."+this.widgetName,this._mouseMoveDelegate).unbind("mouseup."+this.widgetName,this._mouseUpDelegate);if(this._mouseStarted){this._mouseStarted=false;this._preventClickEvent=(j.target==this._mouseDownEvent.target);this._mouseStop(j)}return false},_mouseDistanceMet:function(j){return(Math.max(Math.abs(this._mouseDownEvent.pageX-j.pageX),Math.abs(this._mouseDownEvent.pageY-j.pageY))>=this.options.distance)},_mouseDelayMet:function(j){return this.mouseDelayMet},_mouseStart:function(j){},_mouseDrag:function(j){},_mouseStop:function(j){},_mouseCapture:function(j){return true}};c.ui.mouse.defaults={cancel:null,distance:1,delay:0}})(jQuery);;/* - * jQuery UI Draggable 1.7.2 - * - * Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT (MIT-LICENSE.txt) - * and GPL (GPL-LICENSE.txt) licenses. - * - * http://docs.jquery.com/UI/Draggables - * - * Depends: - * ui.core.js - */ -(function(a){a.widget("ui.draggable",a.extend({},a.ui.mouse,{_init:function(){if(this.options.helper=="original"&&!(/^(?:r|a|f)/).test(this.element.css("position"))){this.element[0].style.position="relative"}(this.options.addClasses&&this.element.addClass("ui-draggable"));(this.options.disabled&&this.element.addClass("ui-draggable-disabled"));this._mouseInit()},destroy:function(){if(!this.element.data("draggable")){return}this.element.removeData("draggable").unbind(".draggable").removeClass("ui-draggable ui-draggable-dragging ui-draggable-disabled");this._mouseDestroy()},_mouseCapture:function(b){var c=this.options;if(this.helper||c.disabled||a(b.target).is(".ui-resizable-handle")){return false}this.handle=this._getHandle(b);if(!this.handle){return false}return true},_mouseStart:function(b){var c=this.options;this.helper=this._createHelper(b);this._cacheHelperProportions();if(a.ui.ddmanager){a.ui.ddmanager.current=this}this._cacheMargins();this.cssPosition=this.helper.css("position");this.scrollParent=this.helper.scrollParent();this.offset=this.element.offset();this.offset={top:this.offset.top-this.margins.top,left:this.offset.left-this.margins.left};a.extend(this.offset,{click:{left:b.pageX-this.offset.left,top:b.pageY-this.offset.top},parent:this._getParentOffset(),relative:this._getRelativeOffset()});this.originalPosition=this._generatePosition(b);this.originalPageX=b.pageX;this.originalPageY=b.pageY;if(c.cursorAt){this._adjustOffsetFromHelper(c.cursorAt)}if(c.containment){this._setContainment()}this._trigger("start",b);this._cacheHelperProportions();if(a.ui.ddmanager&&!c.dropBehaviour){a.ui.ddmanager.prepareOffsets(this,b)}this.helper.addClass("ui-draggable-dragging");this._mouseDrag(b,true);return true},_mouseDrag:function(b,d){this.position=this._generatePosition(b);this.positionAbs=this._convertPositionTo("absolute");if(!d){var c=this._uiHash();this._trigger("drag",b,c);this.position=c.position}if(!this.options.axis||this.options.axis!="y"){this.helper[0].style.left=this.position.left+"px"}if(!this.options.axis||this.options.axis!="x"){this.helper[0].style.top=this.position.top+"px"}if(a.ui.ddmanager){a.ui.ddmanager.drag(this,b)}return false},_mouseStop:function(c){var d=false;if(a.ui.ddmanager&&!this.options.dropBehaviour){d=a.ui.ddmanager.drop(this,c)}if(this.dropped){d=this.dropped;this.dropped=false}if((this.options.revert=="invalid"&&!d)||(this.options.revert=="valid"&&d)||this.options.revert===true||(a.isFunction(this.options.revert)&&this.options.revert.call(this.element,d))){var b=this;a(this.helper).animate(this.originalPosition,parseInt(this.options.revertDuration,10),function(){b._trigger("stop",c);b._clear()})}else{this._trigger("stop",c);this._clear()}return false},_getHandle:function(b){var c=!this.options.handle||!a(this.options.handle,this.element).length?true:false;a(this.options.handle,this.element).find("*").andSelf().each(function(){if(this==b.target){c=true}});return c},_createHelper:function(c){var d=this.options;var b=a.isFunction(d.helper)?a(d.helper.apply(this.element[0],[c])):(d.helper=="clone"?this.element.clone():this.element);if(!b.parents("body").length){b.appendTo((d.appendTo=="parent"?this.element[0].parentNode:d.appendTo))}if(b[0]!=this.element[0]&&!(/(fixed|absolute)/).test(b.css("position"))){b.css("position","absolute")}return b},_adjustOffsetFromHelper:function(b){if(b.left!=undefined){this.offset.click.left=b.left+this.margins.left}if(b.right!=undefined){this.offset.click.left=this.helperProportions.width-b.right+this.margins.left}if(b.top!=undefined){this.offset.click.top=b.top+this.margins.top}if(b.bottom!=undefined){this.offset.click.top=this.helperProportions.height-b.bottom+this.margins.top}},_getParentOffset:function(){this.offsetParent=this.helper.offsetParent();var b=this.offsetParent.offset();if(this.cssPosition=="absolute"&&this.scrollParent[0]!=document&&a.ui.contains(this.scrollParent[0],this.offsetParent[0])){b.left+=this.scrollParent.scrollLeft();b.top+=this.scrollParent.scrollTop()}if((this.offsetParent[0]==document.body)||(this.offsetParent[0].tagName&&this.offsetParent[0].tagName.toLowerCase()=="html"&&a.browser.msie)){b={top:0,left:0}}return{top:b.top+(parseInt(this.offsetParent.css("borderTopWidth"),10)||0),left:b.left+(parseInt(this.offsetParent.css("borderLeftWidth"),10)||0)}},_getRelativeOffset:function(){if(this.cssPosition=="relative"){var b=this.element.position();return{top:b.top-(parseInt(this.helper.css("top"),10)||0)+this.scrollParent.scrollTop(),left:b.left-(parseInt(this.helper.css("left"),10)||0)+this.scrollParent.scrollLeft()}}else{return{top:0,left:0}}},_cacheMargins:function(){this.margins={left:(parseInt(this.element.css("marginLeft"),10)||0),top:(parseInt(this.element.css("marginTop"),10)||0)}},_cacheHelperProportions:function(){this.helperProportions={width:this.helper.outerWidth(),height:this.helper.outerHeight()}},_setContainment:function(){var e=this.options;if(e.containment=="parent"){e.containment=this.helper[0].parentNode}if(e.containment=="document"||e.containment=="window"){this.containment=[0-this.offset.relative.left-this.offset.parent.left,0-this.offset.relative.top-this.offset.parent.top,a(e.containment=="document"?document:window).width()-this.helperProportions.width-this.margins.left,(a(e.containment=="document"?document:window).height()||document.body.parentNode.scrollHeight)-this.helperProportions.height-this.margins.top]}if(!(/^(document|window|parent)$/).test(e.containment)&&e.containment.constructor!=Array){var c=a(e.containment)[0];if(!c){return}var d=a(e.containment).offset();var b=(a(c).css("overflow")!="hidden");this.containment=[d.left+(parseInt(a(c).css("borderLeftWidth"),10)||0)+(parseInt(a(c).css("paddingLeft"),10)||0)-this.margins.left,d.top+(parseInt(a(c).css("borderTopWidth"),10)||0)+(parseInt(a(c).css("paddingTop"),10)||0)-this.margins.top,d.left+(b?Math.max(c.scrollWidth,c.offsetWidth):c.offsetWidth)-(parseInt(a(c).css("borderLeftWidth"),10)||0)-(parseInt(a(c).css("paddingRight"),10)||0)-this.helperProportions.width-this.margins.left,d.top+(b?Math.max(c.scrollHeight,c.offsetHeight):c.offsetHeight)-(parseInt(a(c).css("borderTopWidth"),10)||0)-(parseInt(a(c).css("paddingBottom"),10)||0)-this.helperProportions.height-this.margins.top]}else{if(e.containment.constructor==Array){this.containment=e.containment}}},_convertPositionTo:function(f,h){if(!h){h=this.position}var c=f=="absolute"?1:-1;var e=this.options,b=this.cssPosition=="absolute"&&!(this.scrollParent[0]!=document&&a.ui.contains(this.scrollParent[0],this.offsetParent[0]))?this.offsetParent:this.scrollParent,g=(/(html|body)/i).test(b[0].tagName);return{top:(h.top+this.offset.relative.top*c+this.offset.parent.top*c-(a.browser.safari&&this.cssPosition=="fixed"?0:(this.cssPosition=="fixed"?-this.scrollParent.scrollTop():(g?0:b.scrollTop()))*c)),left:(h.left+this.offset.relative.left*c+this.offset.parent.left*c-(a.browser.safari&&this.cssPosition=="fixed"?0:(this.cssPosition=="fixed"?-this.scrollParent.scrollLeft():g?0:b.scrollLeft())*c))}},_generatePosition:function(e){var h=this.options,b=this.cssPosition=="absolute"&&!(this.scrollParent[0]!=document&&a.ui.contains(this.scrollParent[0],this.offsetParent[0]))?this.offsetParent:this.scrollParent,i=(/(html|body)/i).test(b[0].tagName);if(this.cssPosition=="relative"&&!(this.scrollParent[0]!=document&&this.scrollParent[0]!=this.offsetParent[0])){this.offset.relative=this._getRelativeOffset()}var d=e.pageX;var c=e.pageY;if(this.originalPosition){if(this.containment){if(e.pageX-this.offset.click.leftthis.containment[2]){d=this.containment[2]+this.offset.click.left}if(e.pageY-this.offset.click.top>this.containment[3]){c=this.containment[3]+this.offset.click.top}}if(h.grid){var g=this.originalPageY+Math.round((c-this.originalPageY)/h.grid[1])*h.grid[1];c=this.containment?(!(g-this.offset.click.topthis.containment[3])?g:(!(g-this.offset.click.topthis.containment[2])?f:(!(f-this.offset.click.left').css({width:this.offsetWidth+"px",height:this.offsetHeight+"px",position:"absolute",opacity:"0.001",zIndex:1000}).css(a(this).offset()).appendTo("body")})},stop:function(b,c){a("div.ui-draggable-iframeFix").each(function(){this.parentNode.removeChild(this)})}});a.ui.plugin.add("draggable","opacity",{start:function(c,d){var b=a(d.helper),e=a(this).data("draggable").options;if(b.css("opacity")){e._opacity=b.css("opacity")}b.css("opacity",e.opacity)},stop:function(b,c){var d=a(this).data("draggable").options;if(d._opacity){a(c.helper).css("opacity",d._opacity)}}});a.ui.plugin.add("draggable","scroll",{start:function(c,d){var b=a(this).data("draggable");if(b.scrollParent[0]!=document&&b.scrollParent[0].tagName!="HTML"){b.overflowOffset=b.scrollParent.offset()}},drag:function(d,e){var c=a(this).data("draggable"),f=c.options,b=false;if(c.scrollParent[0]!=document&&c.scrollParent[0].tagName!="HTML"){if(!f.axis||f.axis!="x"){if((c.overflowOffset.top+c.scrollParent[0].offsetHeight)-d.pageY=0;v--){var s=g.snapElements[v].left,n=s+g.snapElements[v].width,m=g.snapElements[v].top,A=m+g.snapElements[v].height;if(!((s-y=p&&n<=k)||(m>=p&&m<=k)||(nk))&&((e>=g&&e<=c)||(d>=g&&d<=c)||(ec));break;default:return false;break}};a.ui.ddmanager={current:null,droppables:{"default":[]},prepareOffsets:function(e,g){var b=a.ui.ddmanager.droppables[e.options.scope];var f=g?g.type:null;var h=(e.currentItem||e.element).find(":data(droppable)").andSelf();droppablesLoop:for(var d=0;d').css({position:this.element.css("position"),width:this.element.outerWidth(),height:this.element.outerHeight(),top:this.element.css("top"),left:this.element.css("left")}));this.element=this.element.parent().data("resizable",this.element.data("resizable"));this.elementIsWrapper=true;this.element.css({marginLeft:this.originalElement.css("marginLeft"),marginTop:this.originalElement.css("marginTop"),marginRight:this.originalElement.css("marginRight"),marginBottom:this.originalElement.css("marginBottom")});this.originalElement.css({marginLeft:0,marginTop:0,marginRight:0,marginBottom:0});this.originalResizeStyle=this.originalElement.css("resize");this.originalElement.css("resize","none");this._proportionallyResizeElements.push(this.originalElement.css({position:"static",zoom:1,display:"block"}));this.originalElement.css({margin:this.originalElement.css("margin")});this._proportionallyResize()}this.handles=j.handles||(!c(".ui-resizable-handle",this.element).length?"e,s,se":{n:".ui-resizable-n",e:".ui-resizable-e",s:".ui-resizable-s",w:".ui-resizable-w",se:".ui-resizable-se",sw:".ui-resizable-sw",ne:".ui-resizable-ne",nw:".ui-resizable-nw"});if(this.handles.constructor==String){if(this.handles=="all"){this.handles="n,e,s,w,se,sw,ne,nw"}var k=this.handles.split(",");this.handles={};for(var f=0;f');if(/sw|se|ne|nw/.test(h)){g.css({zIndex:++j.zIndex})}if("se"==h){g.addClass("ui-icon ui-icon-gripsmall-diagonal-se")}this.handles[h]=".ui-resizable-"+h;this.element.append(g)}}this._renderAxis=function(p){p=p||this.element;for(var m in this.handles){if(this.handles[m].constructor==String){this.handles[m]=c(this.handles[m],this.element).show()}if(this.elementIsWrapper&&this.originalElement[0].nodeName.match(/textarea|input|select|button/i)){var n=c(this.handles[m],this.element),o=0;o=/sw|ne|nw|se|n|s/.test(m)?n.outerHeight():n.outerWidth();var l=["padding",/ne|nw|n/.test(m)?"Top":/se|sw|s/.test(m)?"Bottom":/^e$/.test(m)?"Right":"Left"].join("");p.css(l,o);this._proportionallyResize()}if(!c(this.handles[m]).length){continue}}};this._renderAxis(this.element);this._handles=c(".ui-resizable-handle",this.element).disableSelection();this._handles.mouseover(function(){if(!e.resizing){if(this.className){var i=this.className.match(/ui-resizable-(se|sw|ne|nw|n|e|s|w)/i)}e.axis=i&&i[1]?i[1]:"se"}});if(j.autoHide){this._handles.hide();c(this.element).addClass("ui-resizable-autohide").hover(function(){c(this).removeClass("ui-resizable-autohide");e._handles.show()},function(){if(!e.resizing){c(this).addClass("ui-resizable-autohide");e._handles.hide()}})}this._mouseInit()},destroy:function(){this._mouseDestroy();var d=function(f){c(f).removeClass("ui-resizable ui-resizable-disabled ui-resizable-resizing").removeData("resizable").unbind(".resizable").find(".ui-resizable-handle").remove()};if(this.elementIsWrapper){d(this.element);var e=this.element;e.parent().append(this.originalElement.css({position:e.css("position"),width:e.outerWidth(),height:e.outerHeight(),top:e.css("top"),left:e.css("left")})).end().remove()}this.originalElement.css("resize",this.originalResizeStyle);d(this.originalElement)},_mouseCapture:function(e){var f=false;for(var d in this.handles){if(c(this.handles[d])[0]==e.target){f=true}}return this.options.disabled||!!f},_mouseStart:function(f){var i=this.options,e=this.element.position(),d=this.element;this.resizing=true;this.documentScroll={top:c(document).scrollTop(),left:c(document).scrollLeft()};if(d.is(".ui-draggable")||(/absolute/).test(d.css("position"))){d.css({position:"absolute",top:e.top,left:e.left})}if(c.browser.opera&&(/relative/).test(d.css("position"))){d.css({position:"relative",top:"auto",left:"auto"})}this._renderProxy();var j=b(this.helper.css("left")),g=b(this.helper.css("top"));if(i.containment){j+=c(i.containment).scrollLeft()||0;g+=c(i.containment).scrollTop()||0}this.offset=this.helper.offset();this.position={left:j,top:g};this.size=this._helper?{width:d.outerWidth(),height:d.outerHeight()}:{width:d.width(),height:d.height()};this.originalSize=this._helper?{width:d.outerWidth(),height:d.outerHeight()}:{width:d.width(),height:d.height()};this.originalPosition={left:j,top:g};this.sizeDiff={width:d.outerWidth()-d.width(),height:d.outerHeight()-d.height()};this.originalMousePosition={left:f.pageX,top:f.pageY};this.aspectRatio=(typeof i.aspectRatio=="number")?i.aspectRatio:((this.originalSize.width/this.originalSize.height)||1);var h=c(".ui-resizable-"+this.axis).css("cursor");c("body").css("cursor",h=="auto"?this.axis+"-resize":h);d.addClass("ui-resizable-resizing");this._propagate("start",f);return true},_mouseDrag:function(d){var g=this.helper,f=this.options,l={},p=this,i=this.originalMousePosition,m=this.axis;var q=(d.pageX-i.left)||0,n=(d.pageY-i.top)||0;var h=this._change[m];if(!h){return false}var k=h.apply(this,[d,q,n]),j=c.browser.msie&&c.browser.version<7,e=this.sizeDiff;if(this._aspectRatio||d.shiftKey){k=this._updateRatio(k,d)}k=this._respectSize(k,d);this._propagate("resize",d);g.css({top:this.position.top+"px",left:this.position.left+"px",width:this.size.width+"px",height:this.size.height+"px"});if(!this._helper&&this._proportionallyResizeElements.length){this._proportionallyResize()}this._updateCache(k);this._trigger("resize",d,this.ui());return false},_mouseStop:function(g){this.resizing=false;var h=this.options,l=this;if(this._helper){var f=this._proportionallyResizeElements,d=f.length&&(/textarea/i).test(f[0].nodeName),e=d&&c.ui.hasScroll(f[0],"left")?0:l.sizeDiff.height,j=d?0:l.sizeDiff.width;var m={width:(l.size.width-j),height:(l.size.height-e)},i=(parseInt(l.element.css("left"),10)+(l.position.left-l.originalPosition.left))||null,k=(parseInt(l.element.css("top"),10)+(l.position.top-l.originalPosition.top))||null;if(!h.animate){this.element.css(c.extend(m,{top:k,left:i}))}l.helper.height(l.size.height);l.helper.width(l.size.width);if(this._helper&&!h.animate){this._proportionallyResize()}}c("body").css("cursor","auto");this.element.removeClass("ui-resizable-resizing");this._propagate("stop",g);if(this._helper){this.helper.remove()}return false},_updateCache:function(d){var e=this.options;this.offset=this.helper.offset();if(a(d.left)){this.position.left=d.left}if(a(d.top)){this.position.top=d.top}if(a(d.height)){this.size.height=d.height}if(a(d.width)){this.size.width=d.width}},_updateRatio:function(g,f){var h=this.options,i=this.position,e=this.size,d=this.axis;if(g.height){g.width=(e.height*this.aspectRatio)}else{if(g.width){g.height=(e.width/this.aspectRatio)}}if(d=="sw"){g.left=i.left+(e.width-g.width);g.top=null}if(d=="nw"){g.top=i.top+(e.height-g.height);g.left=i.left+(e.width-g.width)}return g},_respectSize:function(k,f){var i=this.helper,h=this.options,q=this._aspectRatio||f.shiftKey,p=this.axis,s=a(k.width)&&h.maxWidth&&(h.maxWidthk.width),r=a(k.height)&&h.minHeight&&(h.minHeight>k.height);if(g){k.width=h.minWidth}if(r){k.height=h.minHeight}if(s){k.width=h.maxWidth}if(l){k.height=h.maxHeight}var e=this.originalPosition.left+this.originalSize.width,n=this.position.top+this.size.height;var j=/sw|nw|w/.test(p),d=/nw|ne|n/.test(p);if(g&&j){k.left=e-h.minWidth}if(s&&j){k.left=e-h.maxWidth}if(r&&d){k.top=n-h.minHeight}if(l&&d){k.top=n-h.maxHeight}var m=!k.width&&!k.height;if(m&&!k.left&&k.top){k.top=null}else{if(m&&!k.top&&k.left){k.left=null}}return k},_proportionallyResize:function(){var j=this.options;if(!this._proportionallyResizeElements.length){return}var f=this.helper||this.element;for(var e=0;e');var d=c.browser.msie&&c.browser.version<7,f=(d?1:0),g=(d?2:-1);this.helper.addClass(this._helper).css({width:this.element.outerWidth()+g,height:this.element.outerHeight()+g,position:"absolute",left:this.elementOffset.left-f+"px",top:this.elementOffset.top-f+"px",zIndex:++h.zIndex});this.helper.appendTo("body").disableSelection()}else{this.helper=this.element}},_change:{e:function(f,e,d){return{width:this.originalSize.width+e}},w:function(g,e,d){var i=this.options,f=this.originalSize,h=this.originalPosition;return{left:h.left+e,width:f.width-e}},n:function(g,e,d){var i=this.options,f=this.originalSize,h=this.originalPosition;return{top:h.top+d,height:f.height-d}},s:function(f,e,d){return{height:this.originalSize.height+d}},se:function(f,e,d){return c.extend(this._change.s.apply(this,arguments),this._change.e.apply(this,[f,e,d]))},sw:function(f,e,d){return c.extend(this._change.s.apply(this,arguments),this._change.w.apply(this,[f,e,d]))},ne:function(f,e,d){return c.extend(this._change.n.apply(this,arguments),this._change.e.apply(this,[f,e,d]))},nw:function(f,e,d){return c.extend(this._change.n.apply(this,arguments),this._change.w.apply(this,[f,e,d]))}},_propagate:function(e,d){c.ui.plugin.call(this,e,[d,this.ui()]);(e!="resize"&&this._trigger(e,d,this.ui()))},plugins:{},ui:function(){return{originalElement:this.originalElement,element:this.element,helper:this.helper,position:this.position,size:this.size,originalSize:this.originalSize,originalPosition:this.originalPosition}}}));c.extend(c.ui.resizable,{version:"1.7.2",eventPrefix:"resize",defaults:{alsoResize:false,animate:false,animateDuration:"slow",animateEasing:"swing",aspectRatio:false,autoHide:false,cancel:":input,option",containment:false,delay:0,distance:1,ghost:false,grid:false,handles:"e,s,se",helper:false,maxHeight:null,maxWidth:null,minHeight:10,minWidth:10,zIndex:1000}});c.ui.plugin.add("resizable","alsoResize",{start:function(e,f){var d=c(this).data("resizable"),g=d.options;_store=function(h){c(h).each(function(){c(this).data("resizable-alsoresize",{width:parseInt(c(this).width(),10),height:parseInt(c(this).height(),10),left:parseInt(c(this).css("left"),10),top:parseInt(c(this).css("top"),10)})})};if(typeof(g.alsoResize)=="object"&&!g.alsoResize.parentNode){if(g.alsoResize.length){g.alsoResize=g.alsoResize[0];_store(g.alsoResize)}else{c.each(g.alsoResize,function(h,i){_store(h)})}}else{_store(g.alsoResize)}},resize:function(f,h){var e=c(this).data("resizable"),i=e.options,g=e.originalSize,k=e.originalPosition;var j={height:(e.size.height-g.height)||0,width:(e.size.width-g.width)||0,top:(e.position.top-k.top)||0,left:(e.position.left-k.left)||0},d=function(l,m){c(l).each(function(){var p=c(this),q=c(this).data("resizable-alsoresize"),o={},n=m&&m.length?m:["width","height","top","left"];c.each(n||["width","height","top","left"],function(r,t){var s=(q[t]||0)+(j[t]||0);if(s&&s>=0){o[t]=s||null}});if(/relative/.test(p.css("position"))&&c.browser.opera){e._revertToRelativePosition=true;p.css({position:"absolute",top:"auto",left:"auto"})}p.css(o)})};if(typeof(i.alsoResize)=="object"&&!i.alsoResize.nodeType){c.each(i.alsoResize,function(l,m){d(l,m)})}else{d(i.alsoResize)}},stop:function(e,f){var d=c(this).data("resizable");if(d._revertToRelativePosition&&c.browser.opera){d._revertToRelativePosition=false;el.css({position:"relative"})}c(this).removeData("resizable-alsoresize-start")}});c.ui.plugin.add("resizable","animate",{stop:function(h,m){var n=c(this).data("resizable"),i=n.options;var g=n._proportionallyResizeElements,d=g.length&&(/textarea/i).test(g[0].nodeName),e=d&&c.ui.hasScroll(g[0],"left")?0:n.sizeDiff.height,k=d?0:n.sizeDiff.width;var f={width:(n.size.width-k),height:(n.size.height-e)},j=(parseInt(n.element.css("left"),10)+(n.position.left-n.originalPosition.left))||null,l=(parseInt(n.element.css("top"),10)+(n.position.top-n.originalPosition.top))||null;n.element.animate(c.extend(f,l&&j?{top:l,left:j}:{}),{duration:i.animateDuration,easing:i.animateEasing,step:function(){var o={width:parseInt(n.element.css("width"),10),height:parseInt(n.element.css("height"),10),top:parseInt(n.element.css("top"),10),left:parseInt(n.element.css("left"),10)};if(g&&g.length){c(g[0]).css({width:o.width,height:o.height})}n._updateCache(o);n._propagate("resize",h)}})}});c.ui.plugin.add("resizable","containment",{start:function(e,q){var s=c(this).data("resizable"),i=s.options,k=s.element;var f=i.containment,j=(f instanceof c)?f.get(0):(/parent/.test(f))?k.parent().get(0):f;if(!j){return}s.containerElement=c(j);if(/document/.test(f)||f==document){s.containerOffset={left:0,top:0};s.containerPosition={left:0,top:0};s.parentData={element:c(document),left:0,top:0,width:c(document).width(),height:c(document).height()||document.body.parentNode.scrollHeight}}else{var m=c(j),h=[];c(["Top","Right","Left","Bottom"]).each(function(p,o){h[p]=b(m.css("padding"+o))});s.containerOffset=m.offset();s.containerPosition=m.position();s.containerSize={height:(m.innerHeight()-h[3]),width:(m.innerWidth()-h[1])};var n=s.containerOffset,d=s.containerSize.height,l=s.containerSize.width,g=(c.ui.hasScroll(j,"left")?j.scrollWidth:l),r=(c.ui.hasScroll(j)?j.scrollHeight:d);s.parentData={element:j,left:n.left,top:n.top,width:g,height:r}}},resize:function(f,p){var s=c(this).data("resizable"),h=s.options,e=s.containerSize,n=s.containerOffset,l=s.size,m=s.position,q=s._aspectRatio||f.shiftKey,d={top:0,left:0},g=s.containerElement;if(g[0]!=document&&(/static/).test(g.css("position"))){d=n}if(m.left<(s._helper?n.left:0)){s.size.width=s.size.width+(s._helper?(s.position.left-n.left):(s.position.left-d.left));if(q){s.size.height=s.size.width/h.aspectRatio}s.position.left=h.helper?n.left:0}if(m.top<(s._helper?n.top:0)){s.size.height=s.size.height+(s._helper?(s.position.top-n.top):s.position.top);if(q){s.size.width=s.size.height*h.aspectRatio}s.position.top=s._helper?n.top:0}s.offset.left=s.parentData.left+s.position.left;s.offset.top=s.parentData.top+s.position.top;var k=Math.abs((s._helper?s.offset.left-d.left:(s.offset.left-d.left))+s.sizeDiff.width),r=Math.abs((s._helper?s.offset.top-d.top:(s.offset.top-n.top))+s.sizeDiff.height);var j=s.containerElement.get(0)==s.element.parent().get(0),i=/relative|absolute/.test(s.containerElement.css("position"));if(j&&i){k-=s.parentData.left}if(k+s.size.width>=s.parentData.width){s.size.width=s.parentData.width-k;if(q){s.size.height=s.size.width/s.aspectRatio}}if(r+s.size.height>=s.parentData.height){s.size.height=s.parentData.height-r;if(q){s.size.width=s.size.height*s.aspectRatio}}},stop:function(e,m){var p=c(this).data("resizable"),f=p.options,k=p.position,l=p.containerOffset,d=p.containerPosition,g=p.containerElement;var i=c(p.helper),q=i.offset(),n=i.outerWidth()-p.sizeDiff.width,j=i.outerHeight()-p.sizeDiff.height;if(p._helper&&!f.animate&&(/relative/).test(g.css("position"))){c(this).css({left:q.left-d.left-l.left,width:n,height:j})}if(p._helper&&!f.animate&&(/static/).test(g.css("position"))){c(this).css({left:q.left-d.left-l.left,width:n,height:j})}}});c.ui.plugin.add("resizable","ghost",{start:function(f,g){var d=c(this).data("resizable"),h=d.options,e=d.size;d.ghost=d.originalElement.clone();d.ghost.css({opacity:0.25,display:"block",position:"relative",height:e.height,width:e.width,margin:0,left:0,top:0}).addClass("ui-resizable-ghost").addClass(typeof h.ghost=="string"?h.ghost:"");d.ghost.appendTo(d.helper)},resize:function(e,f){var d=c(this).data("resizable"),g=d.options;if(d.ghost){d.ghost.css({position:"relative",height:d.size.height,width:d.size.width})}},stop:function(e,f){var d=c(this).data("resizable"),g=d.options;if(d.ghost&&d.helper){d.helper.get(0).removeChild(d.ghost.get(0))}}});c.ui.plugin.add("resizable","grid",{resize:function(d,l){var n=c(this).data("resizable"),g=n.options,j=n.size,h=n.originalSize,i=n.originalPosition,m=n.axis,k=g._aspectRatio||d.shiftKey;g.grid=typeof g.grid=="number"?[g.grid,g.grid]:g.grid;var f=Math.round((j.width-h.width)/(g.grid[0]||1))*(g.grid[0]||1),e=Math.round((j.height-h.height)/(g.grid[1]||1))*(g.grid[1]||1);if(/^(se|s|e)$/.test(m)){n.size.width=h.width+f;n.size.height=h.height+e}else{if(/^(ne)$/.test(m)){n.size.width=h.width+f;n.size.height=h.height+e;n.position.top=i.top-e}else{if(/^(sw)$/.test(m)){n.size.width=h.width+f;n.size.height=h.height+e;n.position.left=i.left-f}else{n.size.width=h.width+f;n.size.height=h.height+e;n.position.top=i.top-e;n.position.left=i.left-f}}}}});var b=function(d){return parseInt(d,10)||0};var a=function(d){return !isNaN(parseInt(d,10))}})(jQuery);;/* - * jQuery UI Sortable 1.7.2 - * - * Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT (MIT-LICENSE.txt) - * and GPL (GPL-LICENSE.txt) licenses. - * - * http://docs.jquery.com/UI/Sortables - * - * Depends: - * ui.core.js - */ -(function(a){a.widget("ui.sortable",a.extend({},a.ui.mouse,{_init:function(){var b=this.options;this.containerCache={};this.element.addClass("ui-sortable");this.refresh();this.floating=this.items.length?(/left|right/).test(this.items[0].item.css("float")):false;this.offset=this.element.offset();this._mouseInit()},destroy:function(){this.element.removeClass("ui-sortable ui-sortable-disabled").removeData("sortable").unbind(".sortable");this._mouseDestroy();for(var b=this.items.length-1;b>=0;b--){this.items[b].item.removeData("sortable-item")}},_mouseCapture:function(e,f){if(this.reverting){return false}if(this.options.disabled||this.options.type=="static"){return false}this._refreshItems(e);var d=null,c=this,b=a(e.target).parents().each(function(){if(a.data(this,"sortable-item")==c){d=a(this);return false}});if(a.data(e.target,"sortable-item")==c){d=a(e.target)}if(!d){return false}if(this.options.handle&&!f){var g=false;a(this.options.handle,d).find("*").andSelf().each(function(){if(this==e.target){g=true}});if(!g){return false}}this.currentItem=d;this._removeCurrentsFromItems();return true},_mouseStart:function(e,f,b){var g=this.options,c=this;this.currentContainer=this;this.refreshPositions();this.helper=this._createHelper(e);this._cacheHelperProportions();this._cacheMargins();this.scrollParent=this.helper.scrollParent();this.offset=this.currentItem.offset();this.offset={top:this.offset.top-this.margins.top,left:this.offset.left-this.margins.left};this.helper.css("position","absolute");this.cssPosition=this.helper.css("position");a.extend(this.offset,{click:{left:e.pageX-this.offset.left,top:e.pageY-this.offset.top},parent:this._getParentOffset(),relative:this._getRelativeOffset()});this.originalPosition=this._generatePosition(e);this.originalPageX=e.pageX;this.originalPageY=e.pageY;if(g.cursorAt){this._adjustOffsetFromHelper(g.cursorAt)}this.domPosition={prev:this.currentItem.prev()[0],parent:this.currentItem.parent()[0]};if(this.helper[0]!=this.currentItem[0]){this.currentItem.hide()}this._createPlaceholder();if(g.containment){this._setContainment()}if(g.cursor){if(a("body").css("cursor")){this._storedCursor=a("body").css("cursor")}a("body").css("cursor",g.cursor)}if(g.opacity){if(this.helper.css("opacity")){this._storedOpacity=this.helper.css("opacity")}this.helper.css("opacity",g.opacity)}if(g.zIndex){if(this.helper.css("zIndex")){this._storedZIndex=this.helper.css("zIndex")}this.helper.css("zIndex",g.zIndex)}if(this.scrollParent[0]!=document&&this.scrollParent[0].tagName!="HTML"){this.overflowOffset=this.scrollParent.offset()}this._trigger("start",e,this._uiHash());if(!this._preserveHelperProportions){this._cacheHelperProportions()}if(!b){for(var d=this.containers.length-1;d>=0;d--){this.containers[d]._trigger("activate",e,c._uiHash(this))}}if(a.ui.ddmanager){a.ui.ddmanager.current=this}if(a.ui.ddmanager&&!g.dropBehaviour){a.ui.ddmanager.prepareOffsets(this,e)}this.dragging=true;this.helper.addClass("ui-sortable-helper");this._mouseDrag(e);return true},_mouseDrag:function(f){this.position=this._generatePosition(f);this.positionAbs=this._convertPositionTo("absolute");if(!this.lastPositionAbs){this.lastPositionAbs=this.positionAbs}if(this.options.scroll){var g=this.options,b=false;if(this.scrollParent[0]!=document&&this.scrollParent[0].tagName!="HTML"){if((this.overflowOffset.top+this.scrollParent[0].offsetHeight)-f.pageY=0;d--){var e=this.items[d],c=e.item[0],h=this._intersectsWithPointer(e);if(!h){continue}if(c!=this.currentItem[0]&&this.placeholder[h==1?"next":"prev"]()[0]!=c&&!a.ui.contains(this.placeholder[0],c)&&(this.options.type=="semi-dynamic"?!a.ui.contains(this.element[0],c):true)){this.direction=h==1?"down":"up";if(this.options.tolerance=="pointer"||this._intersectsWithSides(e)){this._rearrange(f,e)}else{break}this._trigger("change",f,this._uiHash());break}}this._contactContainers(f);if(a.ui.ddmanager){a.ui.ddmanager.drag(this,f)}this._trigger("sort",f,this._uiHash());this.lastPositionAbs=this.positionAbs;return false},_mouseStop:function(c,d){if(!c){return}if(a.ui.ddmanager&&!this.options.dropBehaviour){a.ui.ddmanager.drop(this,c)}if(this.options.revert){var b=this;var e=b.placeholder.offset();b.reverting=true;a(this.helper).animate({left:e.left-this.offset.parent.left-b.margins.left+(this.offsetParent[0]==document.body?0:this.offsetParent[0].scrollLeft),top:e.top-this.offset.parent.top-b.margins.top+(this.offsetParent[0]==document.body?0:this.offsetParent[0].scrollTop)},parseInt(this.options.revert,10)||500,function(){b._clear(c)})}else{this._clear(c,d)}return false},cancel:function(){var b=this;if(this.dragging){this._mouseUp();if(this.options.helper=="original"){this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper")}else{this.currentItem.show()}for(var c=this.containers.length-1;c>=0;c--){this.containers[c]._trigger("deactivate",null,b._uiHash(this));if(this.containers[c].containerCache.over){this.containers[c]._trigger("out",null,b._uiHash(this));this.containers[c].containerCache.over=0}}}if(this.placeholder[0].parentNode){this.placeholder[0].parentNode.removeChild(this.placeholder[0])}if(this.options.helper!="original"&&this.helper&&this.helper[0].parentNode){this.helper.remove()}a.extend(this,{helper:null,dragging:false,reverting:false,_noFinalSort:null});if(this.domPosition.prev){a(this.domPosition.prev).after(this.currentItem)}else{a(this.domPosition.parent).prepend(this.currentItem)}return true},serialize:function(d){var b=this._getItemsAsjQuery(d&&d.connected);var c=[];d=d||{};a(b).each(function(){var e=(a(d.item||this).attr(d.attribute||"id")||"").match(d.expression||(/(.+)[-=_](.+)/));if(e){c.push((d.key||e[1]+"[]")+"="+(d.key&&d.expression?e[1]:e[2]))}});return c.join("&")},toArray:function(d){var b=this._getItemsAsjQuery(d&&d.connected);var c=[];d=d||{};b.each(function(){c.push(a(d.item||this).attr(d.attribute||"id")||"")});return c},_intersectsWith:function(m){var e=this.positionAbs.left,d=e+this.helperProportions.width,k=this.positionAbs.top,j=k+this.helperProportions.height;var f=m.left,c=f+m.width,n=m.top,i=n+m.height;var o=this.offset.click.top,h=this.offset.click.left;var g=(k+o)>n&&(k+o)f&&(e+h)m[this.floating?"width":"height"])){return g}else{return(f0?"down":"up")},_getDragHorizontalDirection:function(){var b=this.positionAbs.left-this.lastPositionAbs.left;return b!=0&&(b>0?"right":"left")},refresh:function(b){this._refreshItems(b);this.refreshPositions()},_connectWith:function(){var b=this.options;return b.connectWith.constructor==String?[b.connectWith]:b.connectWith},_getItemsAsjQuery:function(b){var l=this;var g=[];var e=[];var h=this._connectWith();if(h&&b){for(var d=h.length-1;d>=0;d--){var k=a(h[d]);for(var c=k.length-1;c>=0;c--){var f=a.data(k[c],"sortable");if(f&&f!=this&&!f.options.disabled){e.push([a.isFunction(f.options.items)?f.options.items.call(f.element):a(f.options.items,f.element).not(".ui-sortable-helper"),f])}}}}e.push([a.isFunction(this.options.items)?this.options.items.call(this.element,null,{options:this.options,item:this.currentItem}):a(this.options.items,this.element).not(".ui-sortable-helper"),this]);for(var d=e.length-1;d>=0;d--){e[d][0].each(function(){g.push(this)})}return a(g)},_removeCurrentsFromItems:function(){var d=this.currentItem.find(":data(sortable-item)");for(var c=0;c=0;e--){var m=a(l[e]);for(var d=m.length-1;d>=0;d--){var g=a.data(m[d],"sortable");if(g&&g!=this&&!g.options.disabled){f.push([a.isFunction(g.options.items)?g.options.items.call(g.element[0],b,{item:this.currentItem}):a(g.options.items,g.element),g]);this.containers.push(g)}}}}for(var e=f.length-1;e>=0;e--){var k=f[e][1];var c=f[e][0];for(var d=0,n=c.length;d=0;d--){var e=this.items[d];if(e.instance!=this.currentContainer&&this.currentContainer&&e.item[0]!=this.currentItem[0]){continue}var c=this.options.toleranceElement?a(this.options.toleranceElement,e.item):e.item;if(!b){e.width=c.outerWidth();e.height=c.outerHeight()}var f=c.offset();e.left=f.left;e.top=f.top}if(this.options.custom&&this.options.custom.refreshContainers){this.options.custom.refreshContainers.call(this)}else{for(var d=this.containers.length-1;d>=0;d--){var f=this.containers[d].element.offset();this.containers[d].containerCache.left=f.left;this.containers[d].containerCache.top=f.top;this.containers[d].containerCache.width=this.containers[d].element.outerWidth();this.containers[d].containerCache.height=this.containers[d].element.outerHeight()}}},_createPlaceholder:function(d){var b=d||this,e=b.options;if(!e.placeholder||e.placeholder.constructor==String){var c=e.placeholder;e.placeholder={element:function(){var f=a(document.createElement(b.currentItem[0].nodeName)).addClass(c||b.currentItem[0].className+" ui-sortable-placeholder").removeClass("ui-sortable-helper")[0];if(!c){f.style.visibility="hidden"}return f},update:function(f,g){if(c&&!e.forcePlaceholderSize){return}if(!g.height()){g.height(b.currentItem.innerHeight()-parseInt(b.currentItem.css("paddingTop")||0,10)-parseInt(b.currentItem.css("paddingBottom")||0,10))}if(!g.width()){g.width(b.currentItem.innerWidth()-parseInt(b.currentItem.css("paddingLeft")||0,10)-parseInt(b.currentItem.css("paddingRight")||0,10))}}}}b.placeholder=a(e.placeholder.element.call(b.element,b.currentItem));b.currentItem.after(b.placeholder);e.placeholder.update(b,b.placeholder)},_contactContainers:function(d){for(var c=this.containers.length-1;c>=0;c--){if(this._intersectsWith(this.containers[c].containerCache)){if(!this.containers[c].containerCache.over){if(this.currentContainer!=this.containers[c]){var h=10000;var g=null;var e=this.positionAbs[this.containers[c].floating?"left":"top"];for(var b=this.items.length-1;b>=0;b--){if(!a.ui.contains(this.containers[c].element[0],this.items[b].item[0])){continue}var f=this.items[b][this.containers[c].floating?"left":"top"];if(Math.abs(f-e)this.containment[2]){d=this.containment[2]+this.offset.click.left}if(e.pageY-this.offset.click.top>this.containment[3]){c=this.containment[3]+this.offset.click.top}}if(h.grid){var g=this.originalPageY+Math.round((c-this.originalPageY)/h.grid[1])*h.grid[1];c=this.containment?(!(g-this.offset.click.topthis.containment[3])?g:(!(g-this.offset.click.topthis.containment[2])?f:(!(f-this.offset.click.left=0;c--){if(a.ui.contains(this.containers[c].element[0],this.currentItem[0])&&!e){f.push((function(g){return function(h){g._trigger("receive",h,this._uiHash(this))}}).call(this,this.containers[c]));f.push((function(g){return function(h){g._trigger("update",h,this._uiHash(this))}}).call(this,this.containers[c]))}}}for(var c=this.containers.length-1;c>=0;c--){if(!e){f.push((function(g){return function(h){g._trigger("deactivate",h,this._uiHash(this))}}).call(this,this.containers[c]))}if(this.containers[c].containerCache.over){f.push((function(g){return function(h){g._trigger("out",h,this._uiHash(this))}}).call(this,this.containers[c]));this.containers[c].containerCache.over=0}}if(this._storedCursor){a("body").css("cursor",this._storedCursor)}if(this._storedOpacity){this.helper.css("opacity",this._storedOpacity)}if(this._storedZIndex){this.helper.css("zIndex",this._storedZIndex=="auto"?"":this._storedZIndex)}this.dragging=false;if(this.cancelHelperRemoval){if(!e){this._trigger("beforeStop",d,this._uiHash());for(var c=0;c *",opacity:false,placeholder:false,revert:false,scroll:true,scrollSensitivity:20,scrollSpeed:20,scope:"default",tolerance:"intersect",zIndex:1000}})})(jQuery);;/* - * jQuery UI Accordion 1.7.2 - * - * Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT (MIT-LICENSE.txt) - * and GPL (GPL-LICENSE.txt) licenses. - * - * http://docs.jquery.com/UI/Accordion - * - * Depends: - * ui.core.js - */ -(function(a){a.widget("ui.accordion",{_init:function(){var d=this.options,b=this;this.running=0;if(d.collapsible==a.ui.accordion.defaults.collapsible&&d.alwaysOpen!=a.ui.accordion.defaults.alwaysOpen){d.collapsible=!d.alwaysOpen}if(d.navigation){var c=this.element.find("a").filter(d.navigationFilter);if(c.length){if(c.filter(d.header).length){this.active=c}else{this.active=c.parent().parent().prev();c.addClass("ui-accordion-content-active")}}}this.element.addClass("ui-accordion ui-widget ui-helper-reset");if(this.element[0].nodeName=="UL"){this.element.children("li").addClass("ui-accordion-li-fix")}this.headers=this.element.find(d.header).addClass("ui-accordion-header ui-helper-reset ui-state-default ui-corner-all").bind("mouseenter.accordion",function(){a(this).addClass("ui-state-hover")}).bind("mouseleave.accordion",function(){a(this).removeClass("ui-state-hover")}).bind("focus.accordion",function(){a(this).addClass("ui-state-focus")}).bind("blur.accordion",function(){a(this).removeClass("ui-state-focus")});this.headers.next().addClass("ui-accordion-content ui-helper-reset ui-widget-content ui-corner-bottom");this.active=this._findActive(this.active||d.active).toggleClass("ui-state-default").toggleClass("ui-state-active").toggleClass("ui-corner-all").toggleClass("ui-corner-top");this.active.next().addClass("ui-accordion-content-active");a("").addClass("ui-icon "+d.icons.header).prependTo(this.headers);this.active.find(".ui-icon").toggleClass(d.icons.header).toggleClass(d.icons.headerSelected);if(a.browser.msie){this.element.find("a").css("zoom","1")}this.resize();this.element.attr("role","tablist");this.headers.attr("role","tab").bind("keydown",function(e){return b._keydown(e)}).next().attr("role","tabpanel");this.headers.not(this.active||"").attr("aria-expanded","false").attr("tabIndex","-1").next().hide();if(!this.active.length){this.headers.eq(0).attr("tabIndex","0")}else{this.active.attr("aria-expanded","true").attr("tabIndex","0")}if(!a.browser.safari){this.headers.find("a").attr("tabIndex","-1")}if(d.event){this.headers.bind((d.event)+".accordion",function(e){return b._clickHandler.call(b,e,this)})}},destroy:function(){var c=this.options;this.element.removeClass("ui-accordion ui-widget ui-helper-reset").removeAttr("role").unbind(".accordion").removeData("accordion");this.headers.unbind(".accordion").removeClass("ui-accordion-header ui-helper-reset ui-state-default ui-corner-all ui-state-active ui-corner-top").removeAttr("role").removeAttr("aria-expanded").removeAttr("tabindex");this.headers.find("a").removeAttr("tabindex");this.headers.children(".ui-icon").remove();var b=this.headers.next().css("display","").removeAttr("role").removeClass("ui-helper-reset ui-widget-content ui-corner-bottom ui-accordion-content ui-accordion-content-active");if(c.autoHeight||c.fillHeight){b.css("height","")}},_setData:function(b,c){if(b=="alwaysOpen"){b="collapsible";c=!c}a.widget.prototype._setData.apply(this,arguments)},_keydown:function(e){var g=this.options,f=a.ui.keyCode;if(g.disabled||e.altKey||e.ctrlKey){return}var d=this.headers.length;var b=this.headers.index(e.target);var c=false;switch(e.keyCode){case f.RIGHT:case f.DOWN:c=this.headers[(b+1)%d];break;case f.LEFT:case f.UP:c=this.headers[(b-1+d)%d];break;case f.SPACE:case f.ENTER:return this._clickHandler({target:e.target},e.target)}if(c){a(e.target).attr("tabIndex","-1");a(c).attr("tabIndex","0");c.focus();return false}return true},resize:function(){var e=this.options,d;if(e.fillSpace){if(a.browser.msie){var b=this.element.parent().css("overflow");this.element.parent().css("overflow","hidden")}d=this.element.parent().height();if(a.browser.msie){this.element.parent().css("overflow",b)}this.headers.each(function(){d-=a(this).outerHeight()});var c=0;this.headers.next().each(function(){c=Math.max(c,a(this).innerHeight()-a(this).height())}).height(Math.max(0,d-c)).css("overflow","auto")}else{if(e.autoHeight){d=0;this.headers.next().each(function(){d=Math.max(d,a(this).outerHeight())}).height(d)}}},activate:function(b){var c=this._findActive(b)[0];this._clickHandler({target:c},c)},_findActive:function(b){return b?typeof b=="number"?this.headers.filter(":eq("+b+")"):this.headers.not(this.headers.not(b)):b===false?a([]):this.headers.filter(":eq(0)")},_clickHandler:function(b,f){var d=this.options;if(d.disabled){return false}if(!b.target&&d.collapsible){this.active.removeClass("ui-state-active ui-corner-top").addClass("ui-state-default ui-corner-all").find(".ui-icon").removeClass(d.icons.headerSelected).addClass(d.icons.header);this.active.next().addClass("ui-accordion-content-active");var h=this.active.next(),e={options:d,newHeader:a([]),oldHeader:d.active,newContent:a([]),oldContent:h},c=(this.active=a([]));this._toggle(c,h,e);return false}var g=a(b.currentTarget||f);var i=g[0]==this.active[0];if(this.running||(!d.collapsible&&i)){return false}this.active.removeClass("ui-state-active ui-corner-top").addClass("ui-state-default ui-corner-all").find(".ui-icon").removeClass(d.icons.headerSelected).addClass(d.icons.header);this.active.next().addClass("ui-accordion-content-active");if(!i){g.removeClass("ui-state-default ui-corner-all").addClass("ui-state-active ui-corner-top").find(".ui-icon").removeClass(d.icons.header).addClass(d.icons.headerSelected);g.next().addClass("ui-accordion-content-active")}var c=g.next(),h=this.active.next(),e={options:d,newHeader:i&&d.collapsible?a([]):g,oldHeader:this.active,newContent:i&&d.collapsible?a([]):c.find("> *"),oldContent:h.find("> *")},j=this.headers.index(this.active[0])>this.headers.index(g[0]);this.active=i?a([]):g;this._toggle(c,h,e,i,j);return false},_toggle:function(b,i,g,j,k){var d=this.options,m=this;this.toShow=b;this.toHide=i;this.data=g;var c=function(){if(!m){return}return m._completed.apply(m,arguments)};this._trigger("changestart",null,this.data);this.running=i.size()===0?b.size():i.size();if(d.animated){var f={};if(d.collapsible&&j){f={toShow:a([]),toHide:i,complete:c,down:k,autoHeight:d.autoHeight||d.fillSpace}}else{f={toShow:b,toHide:i,complete:c,down:k,autoHeight:d.autoHeight||d.fillSpace}}if(!d.proxied){d.proxied=d.animated}if(!d.proxiedDuration){d.proxiedDuration=d.duration}d.animated=a.isFunction(d.proxied)?d.proxied(f):d.proxied;d.duration=a.isFunction(d.proxiedDuration)?d.proxiedDuration(f):d.proxiedDuration;var l=a.ui.accordion.animations,e=d.duration,h=d.animated;if(!l[h]){l[h]=function(n){this.slide(n,{easing:h,duration:e||700})}}l[h](f)}else{if(d.collapsible&&j){b.toggle()}else{i.hide();b.show()}c(true)}i.prev().attr("aria-expanded","false").attr("tabIndex","-1").blur();b.prev().attr("aria-expanded","true").attr("tabIndex","0").focus()},_completed:function(b){var c=this.options;this.running=b?0:--this.running;if(this.running){return}if(c.clearStyle){this.toShow.add(this.toHide).css({height:"",overflow:""})}this._trigger("change",null,this.data)}});a.extend(a.ui.accordion,{version:"1.7.2",defaults:{active:null,alwaysOpen:true,animated:"slide",autoHeight:true,clearStyle:false,collapsible:false,event:"click",fillSpace:false,header:"> li > :first-child,> :not(li):even",icons:{header:"ui-icon-triangle-1-e",headerSelected:"ui-icon-triangle-1-s"},navigation:false,navigationFilter:function(){return this.href.toLowerCase()==location.href.toLowerCase()}},animations:{slide:function(j,h){j=a.extend({easing:"swing",duration:300},j,h);if(!j.toHide.size()){j.toShow.animate({height:"show"},j);return}if(!j.toShow.size()){j.toHide.animate({height:"hide"},j);return}var c=j.toShow.css("overflow"),g,d={},f={},e=["height","paddingTop","paddingBottom"],b;var i=j.toShow;b=i[0].style.width;i.width(parseInt(i.parent().width(),10)-parseInt(i.css("paddingLeft"),10)-parseInt(i.css("paddingRight"),10)-(parseInt(i.css("borderLeftWidth"),10)||0)-(parseInt(i.css("borderRightWidth"),10)||0));a.each(e,function(k,m){f[m]="hide";var l=(""+a.css(j.toShow[0],m)).match(/^([\d+-.]+)(.*)$/);d[m]={value:l[1],unit:l[2]||"px"}});j.toShow.css({height:0,overflow:"hidden"}).show();j.toHide.filter(":hidden").each(j.complete).end().filter(":visible").animate(f,{step:function(k,l){if(l.prop=="height"){g=(l.now-l.start)/(l.end-l.start)}j.toShow[0].style[l.prop]=(g*d[l.prop].value)+d[l.prop].unit},duration:j.duration,easing:j.easing,complete:function(){if(!j.autoHeight){j.toShow.css("height","")}j.toShow.css("width",b);j.toShow.css({overflow:c});j.complete()}})},bounceslide:function(b){this.slide(b,{easing:b.down?"easeOutBounce":"swing",duration:b.down?1000:200})},easeslide:function(b){this.slide(b,{easing:"easeinout",duration:700})}}})})(jQuery);;/* - * jQuery UI Dialog 1.7.2 - * - * Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT (MIT-LICENSE.txt) - * and GPL (GPL-LICENSE.txt) licenses. - * - * http://docs.jquery.com/UI/Dialog - * - * Depends: - * ui.core.js - * ui.draggable.js - * ui.resizable.js - */ -(function(c){var b={dragStart:"start.draggable",drag:"drag.draggable",dragStop:"stop.draggable",maxHeight:"maxHeight.resizable",minHeight:"minHeight.resizable",maxWidth:"maxWidth.resizable",minWidth:"minWidth.resizable",resizeStart:"start.resizable",resize:"drag.resizable",resizeStop:"stop.resizable"},a="ui-dialog ui-widget ui-widget-content ui-corner-all ";c.widget("ui.dialog",{_init:function(){this.originalTitle=this.element.attr("title");var l=this,m=this.options,j=m.title||this.originalTitle||" ",e=c.ui.dialog.getTitleId(this.element),k=(this.uiDialog=c("
                ")).appendTo(document.body).hide().addClass(a+m.dialogClass).css({position:"absolute",overflow:"hidden",zIndex:m.zIndex}).attr("tabIndex",-1).css("outline",0).keydown(function(n){(m.closeOnEscape&&n.keyCode&&n.keyCode==c.ui.keyCode.ESCAPE&&l.close(n))}).attr({role:"dialog","aria-labelledby":e}).mousedown(function(n){l.moveToTop(false,n)}),g=this.element.show().removeAttr("title").addClass("ui-dialog-content ui-widget-content").appendTo(k),f=(this.uiDialogTitlebar=c("
                ")).addClass("ui-dialog-titlebar ui-widget-header ui-corner-all ui-helper-clearfix").prependTo(k),i=c('').addClass("ui-dialog-titlebar-close ui-corner-all").attr("role","button").hover(function(){i.addClass("ui-state-hover")},function(){i.removeClass("ui-state-hover")}).focus(function(){i.addClass("ui-state-focus")}).blur(function(){i.removeClass("ui-state-focus")}).mousedown(function(n){n.stopPropagation()}).click(function(n){l.close(n);return false}).appendTo(f),h=(this.uiDialogTitlebarCloseText=c("")).addClass("ui-icon ui-icon-closethick").text(m.closeText).appendTo(i),d=c("").addClass("ui-dialog-title").attr("id",e).html(j).prependTo(f);f.find("*").add(f).disableSelection();(m.draggable&&c.fn.draggable&&this._makeDraggable());(m.resizable&&c.fn.resizable&&this._makeResizable());this._createButtons(m.buttons);this._isOpen=false;(m.bgiframe&&c.fn.bgiframe&&k.bgiframe());(m.autoOpen&&this.open())},destroy:function(){(this.overlay&&this.overlay.destroy());this.uiDialog.hide();this.element.unbind(".dialog").removeData("dialog").removeClass("ui-dialog-content ui-widget-content").hide().appendTo("body");this.uiDialog.remove();(this.originalTitle&&this.element.attr("title",this.originalTitle))},close:function(f){var d=this;if(false===d._trigger("beforeclose",f)){return}(d.overlay&&d.overlay.destroy());d.uiDialog.unbind("keypress.ui-dialog");(d.options.hide?d.uiDialog.hide(d.options.hide,function(){d._trigger("close",f)}):d.uiDialog.hide()&&d._trigger("close",f));c.ui.dialog.overlay.resize();d._isOpen=false;if(d.options.modal){var e=0;c(".ui-dialog").each(function(){if(this!=d.uiDialog[0]){e=Math.max(e,c(this).css("z-index"))}});c.ui.dialog.maxZ=e}},isOpen:function(){return this._isOpen},moveToTop:function(f,e){if((this.options.modal&&!f)||(!this.options.stack&&!this.options.modal)){return this._trigger("focus",e)}if(this.options.zIndex>c.ui.dialog.maxZ){c.ui.dialog.maxZ=this.options.zIndex}(this.overlay&&this.overlay.$el.css("z-index",c.ui.dialog.overlay.maxZ=++c.ui.dialog.maxZ));var d={scrollTop:this.element.attr("scrollTop"),scrollLeft:this.element.attr("scrollLeft")};this.uiDialog.css("z-index",++c.ui.dialog.maxZ);this.element.attr(d);this._trigger("focus",e)},open:function(){if(this._isOpen){return}var e=this.options,d=this.uiDialog;this.overlay=e.modal?new c.ui.dialog.overlay(this):null;(d.next().length&&d.appendTo("body"));this._size();this._position(e.position);d.show(e.show);this.moveToTop(true);(e.modal&&d.bind("keypress.ui-dialog",function(h){if(h.keyCode!=c.ui.keyCode.TAB){return}var g=c(":tabbable",this),i=g.filter(":first")[0],f=g.filter(":last")[0];if(h.target==f&&!h.shiftKey){setTimeout(function(){i.focus()},1)}else{if(h.target==i&&h.shiftKey){setTimeout(function(){f.focus()},1)}}}));c([]).add(d.find(".ui-dialog-content :tabbable:first")).add(d.find(".ui-dialog-buttonpane :tabbable:first")).add(d).filter(":first").focus();this._trigger("open");this._isOpen=true},_createButtons:function(g){var f=this,d=false,e=c("
                ").addClass("ui-dialog-buttonpane ui-widget-content ui-helper-clearfix");this.uiDialog.find(".ui-dialog-buttonpane").remove();(typeof g=="object"&&g!==null&&c.each(g,function(){return !(d=true)}));if(d){c.each(g,function(h,i){c('').addClass("ui-state-default ui-corner-all").text(h).click(function(){i.apply(f.element[0],arguments)}).hover(function(){c(this).addClass("ui-state-hover")},function(){c(this).removeClass("ui-state-hover")}).focus(function(){c(this).addClass("ui-state-focus")}).blur(function(){c(this).removeClass("ui-state-focus")}).appendTo(e)});e.appendTo(this.uiDialog)}},_makeDraggable:function(){var d=this,f=this.options,e;this.uiDialog.draggable({cancel:".ui-dialog-content",handle:".ui-dialog-titlebar",containment:"document",start:function(){e=f.height;c(this).height(c(this).height()).addClass("ui-dialog-dragging");(f.dragStart&&f.dragStart.apply(d.element[0],arguments))},drag:function(){(f.drag&&f.drag.apply(d.element[0],arguments))},stop:function(){c(this).removeClass("ui-dialog-dragging").height(e);(f.dragStop&&f.dragStop.apply(d.element[0],arguments));c.ui.dialog.overlay.resize()}})},_makeResizable:function(g){g=(g===undefined?this.options.resizable:g);var d=this,f=this.options,e=typeof g=="string"?g:"n,e,s,w,se,sw,ne,nw";this.uiDialog.resizable({cancel:".ui-dialog-content",alsoResize:this.element,maxWidth:f.maxWidth,maxHeight:f.maxHeight,minWidth:f.minWidth,minHeight:f.minHeight,start:function(){c(this).addClass("ui-dialog-resizing");(f.resizeStart&&f.resizeStart.apply(d.element[0],arguments))},resize:function(){(f.resize&&f.resize.apply(d.element[0],arguments))},handles:e,stop:function(){c(this).removeClass("ui-dialog-resizing");f.height=c(this).height();f.width=c(this).width();(f.resizeStop&&f.resizeStop.apply(d.element[0],arguments));c.ui.dialog.overlay.resize()}}).find(".ui-resizable-se").addClass("ui-icon ui-icon-grip-diagonal-se")},_position:function(i){var e=c(window),f=c(document),g=f.scrollTop(),d=f.scrollLeft(),h=g;if(c.inArray(i,["center","top","right","bottom","left"])>=0){i=[i=="right"||i=="left"?i:"center",i=="top"||i=="bottom"?i:"middle"]}if(i.constructor!=Array){i=["center","middle"]}if(i[0].constructor==Number){d+=i[0]}else{switch(i[0]){case"left":d+=0;break;case"right":d+=e.width()-this.uiDialog.outerWidth();break;default:case"center":d+=(e.width()-this.uiDialog.outerWidth())/2}}if(i[1].constructor==Number){g+=i[1]}else{switch(i[1]){case"top":g+=0;break;case"bottom":g+=e.height()-this.uiDialog.outerHeight();break;default:case"middle":g+=(e.height()-this.uiDialog.outerHeight())/2}}g=Math.max(g,h);this.uiDialog.css({top:g,left:d})},_setData:function(e,f){(b[e]&&this.uiDialog.data(b[e],f));switch(e){case"buttons":this._createButtons(f);break;case"closeText":this.uiDialogTitlebarCloseText.text(f);break;case"dialogClass":this.uiDialog.removeClass(this.options.dialogClass).addClass(a+f);break;case"draggable":(f?this._makeDraggable():this.uiDialog.draggable("destroy"));break;case"height":this.uiDialog.height(f);break;case"position":this._position(f);break;case"resizable":var d=this.uiDialog,g=this.uiDialog.is(":data(resizable)");(g&&!f&&d.resizable("destroy"));(g&&typeof f=="string"&&d.resizable("option","handles",f));(g||this._makeResizable(f));break;case"title":c(".ui-dialog-title",this.uiDialogTitlebar).html(f||" ");break;case"width":this.uiDialog.width(f);break}c.widget.prototype._setData.apply(this,arguments)},_size:function(){var e=this.options;this.element.css({height:0,minHeight:0,width:"auto"});var d=this.uiDialog.css({height:"auto",width:e.width}).height();this.element.css({minHeight:Math.max(e.minHeight-d,0),height:e.height=="auto"?"auto":Math.max(e.height-d,0)})}});c.extend(c.ui.dialog,{version:"1.7.2",defaults:{autoOpen:true,bgiframe:false,buttons:{},closeOnEscape:true,closeText:"close",dialogClass:"",draggable:true,hide:null,height:"auto",maxHeight:false,maxWidth:false,minHeight:150,minWidth:150,modal:false,position:"center",resizable:true,show:null,stack:true,title:"",width:300,zIndex:1000},getter:"isOpen",uuid:0,maxZ:0,getTitleId:function(d){return"ui-dialog-title-"+(d.attr("id")||++this.uuid)},overlay:function(d){this.$el=c.ui.dialog.overlay.create(d)}});c.extend(c.ui.dialog.overlay,{instances:[],maxZ:0,events:c.map("focus,mousedown,mouseup,keydown,keypress,click".split(","),function(d){return d+".dialog-overlay"}).join(" "),create:function(e){if(this.instances.length===0){setTimeout(function(){if(c.ui.dialog.overlay.instances.length){c(document).bind(c.ui.dialog.overlay.events,function(f){var g=c(f.target).parents(".ui-dialog").css("zIndex")||0;return(g>c.ui.dialog.overlay.maxZ)})}},1);c(document).bind("keydown.dialog-overlay",function(f){(e.options.closeOnEscape&&f.keyCode&&f.keyCode==c.ui.keyCode.ESCAPE&&e.close(f))});c(window).bind("resize.dialog-overlay",c.ui.dialog.overlay.resize)}var d=c("
                ").appendTo(document.body).addClass("ui-widget-overlay").css({width:this.width(),height:this.height()});(e.options.bgiframe&&c.fn.bgiframe&&d.bgiframe());this.instances.push(d);return d},destroy:function(d){this.instances.splice(c.inArray(this.instances,d),1);if(this.instances.length===0){c([document,window]).unbind(".dialog-overlay")}d.remove();var e=0;c.each(this.instances,function(){e=Math.max(e,this.css("z-index"))});this.maxZ=e},height:function(){if(c.browser.msie&&c.browser.version<7){var e=Math.max(document.documentElement.scrollHeight,document.body.scrollHeight);var d=Math.max(document.documentElement.offsetHeight,document.body.offsetHeight);if(e=0&&this.anchors[d.selected])||d.selected<0)?d.selected:0;d.disabled=a.unique(d.disabled.concat(a.map(this.lis.filter(".ui-state-disabled"),function(q,o){return p.lis.index(q)}))).sort();if(a.inArray(d.selected,d.disabled)!=-1){d.disabled.splice(a.inArray(d.selected,d.disabled),1)}this.panels.addClass("ui-tabs-hide");this.lis.removeClass("ui-tabs-selected ui-state-active");if(d.selected>=0&&this.anchors.length){this.panels.eq(d.selected).removeClass("ui-tabs-hide");this.lis.eq(d.selected).addClass("ui-tabs-selected ui-state-active");p.element.queue("tabs",function(){p._trigger("show",null,p._ui(p.anchors[d.selected],p.panels[d.selected]))});this.load(d.selected)}a(window).bind("unload",function(){p.lis.add(p.anchors).unbind(".tabs");p.lis=p.anchors=p.panels=null})}else{d.selected=this.lis.index(this.lis.filter(".ui-tabs-selected"))}this.element[d.collapsible?"addClass":"removeClass"]("ui-tabs-collapsible");if(d.cookie){this._cookie(d.selected,d.cookie)}for(var g=0,m;(m=this.lis[g]);g++){a(m)[a.inArray(g,d.disabled)!=-1&&!a(m).hasClass("ui-tabs-selected")?"addClass":"removeClass"]("ui-state-disabled")}if(d.cache===false){this.anchors.removeData("cache.tabs")}this.lis.add(this.anchors).unbind(".tabs");if(d.event!="mouseover"){var f=function(o,i){if(i.is(":not(.ui-state-disabled)")){i.addClass("ui-state-"+o)}};var j=function(o,i){i.removeClass("ui-state-"+o)};this.lis.bind("mouseover.tabs",function(){f("hover",a(this))});this.lis.bind("mouseout.tabs",function(){j("hover",a(this))});this.anchors.bind("focus.tabs",function(){f("focus",a(this).closest("li"))});this.anchors.bind("blur.tabs",function(){j("focus",a(this).closest("li"))})}var b,h;if(d.fx){if(a.isArray(d.fx)){b=d.fx[0];h=d.fx[1]}else{b=h=d.fx}}function e(i,o){i.css({display:""});if(a.browser.msie&&o.opacity){i[0].style.removeAttribute("filter")}}var k=h?function(i,o){a(i).closest("li").removeClass("ui-state-default").addClass("ui-tabs-selected ui-state-active");o.hide().removeClass("ui-tabs-hide").animate(h,h.duration||"normal",function(){e(o,h);p._trigger("show",null,p._ui(i,o[0]))})}:function(i,o){a(i).closest("li").removeClass("ui-state-default").addClass("ui-tabs-selected ui-state-active");o.removeClass("ui-tabs-hide");p._trigger("show",null,p._ui(i,o[0]))};var l=b?function(o,i){i.animate(b,b.duration||"normal",function(){p.lis.removeClass("ui-tabs-selected ui-state-active").addClass("ui-state-default");i.addClass("ui-tabs-hide");e(i,b);p.element.dequeue("tabs")})}:function(o,i,q){p.lis.removeClass("ui-tabs-selected ui-state-active").addClass("ui-state-default");i.addClass("ui-tabs-hide");p.element.dequeue("tabs")};this.anchors.bind(d.event+".tabs",function(){var o=this,r=a(this).closest("li"),i=p.panels.filter(":not(.ui-tabs-hide)"),q=a(p._sanitizeSelector(this.hash));if((r.hasClass("ui-tabs-selected")&&!d.collapsible)||r.hasClass("ui-state-disabled")||r.hasClass("ui-state-processing")||p._trigger("select",null,p._ui(this,q[0]))===false){this.blur();return false}d.selected=p.anchors.index(this);p.abort();if(d.collapsible){if(r.hasClass("ui-tabs-selected")){d.selected=-1;if(d.cookie){p._cookie(d.selected,d.cookie)}p.element.queue("tabs",function(){l(o,i)}).dequeue("tabs");this.blur();return false}else{if(!i.length){if(d.cookie){p._cookie(d.selected,d.cookie)}p.element.queue("tabs",function(){k(o,q)});p.load(p.anchors.index(this));this.blur();return false}}}if(d.cookie){p._cookie(d.selected,d.cookie)}if(q.length){if(i.length){p.element.queue("tabs",function(){l(o,i)})}p.element.queue("tabs",function(){k(o,q)});p.load(p.anchors.index(this))}else{throw"jQuery UI Tabs: Mismatching fragment identifier."}if(a.browser.msie){this.blur()}});this.anchors.bind("click.tabs",function(){return false})},destroy:function(){var b=this.options;this.abort();this.element.unbind(".tabs").removeClass("ui-tabs ui-widget ui-widget-content ui-corner-all ui-tabs-collapsible").removeData("tabs");this.list.removeClass("ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all");this.anchors.each(function(){var c=a.data(this,"href.tabs");if(c){this.href=c}var d=a(this).unbind(".tabs");a.each(["href","load","cache"],function(e,f){d.removeData(f+".tabs")})});this.lis.unbind(".tabs").add(this.panels).each(function(){if(a.data(this,"destroy.tabs")){a(this).remove()}else{a(this).removeClass(["ui-state-default","ui-corner-top","ui-tabs-selected","ui-state-active","ui-state-hover","ui-state-focus","ui-state-disabled","ui-tabs-panel","ui-widget-content","ui-corner-bottom","ui-tabs-hide"].join(" "))}});if(b.cookie){this._cookie(null,b.cookie)}},add:function(e,d,c){if(c===undefined){c=this.anchors.length}var b=this,g=this.options,i=a(g.tabTemplate.replace(/#\{href\}/g,e).replace(/#\{label\}/g,d)),h=!e.indexOf("#")?e.replace("#",""):this._tabId(a("a",i)[0]);i.addClass("ui-state-default ui-corner-top").data("destroy.tabs",true);var f=a("#"+h);if(!f.length){f=a(g.panelTemplate).attr("id",h).data("destroy.tabs",true)}f.addClass("ui-tabs-panel ui-widget-content ui-corner-bottom ui-tabs-hide");if(c>=this.lis.length){i.appendTo(this.list);f.appendTo(this.list[0].parentNode)}else{i.insertBefore(this.lis[c]);f.insertBefore(this.panels[c])}g.disabled=a.map(g.disabled,function(k,j){return k>=c?++k:k});this._tabify();if(this.anchors.length==1){i.addClass("ui-tabs-selected ui-state-active");f.removeClass("ui-tabs-hide");this.element.queue("tabs",function(){b._trigger("show",null,b._ui(b.anchors[0],b.panels[0]))});this.load(0)}this._trigger("add",null,this._ui(this.anchors[c],this.panels[c]))},remove:function(b){var d=this.options,e=this.lis.eq(b).remove(),c=this.panels.eq(b).remove();if(e.hasClass("ui-tabs-selected")&&this.anchors.length>1){this.select(b+(b+1=b?--g:g});this._tabify();this._trigger("remove",null,this._ui(e.find("a")[0],c[0]))},enable:function(b){var c=this.options;if(a.inArray(b,c.disabled)==-1){return}this.lis.eq(b).removeClass("ui-state-disabled");c.disabled=a.grep(c.disabled,function(e,d){return e!=b});this._trigger("enable",null,this._ui(this.anchors[b],this.panels[b]))},disable:function(c){var b=this,d=this.options;if(c!=d.selected){this.lis.eq(c).addClass("ui-state-disabled");d.disabled.push(c);d.disabled.sort();this._trigger("disable",null,this._ui(this.anchors[c],this.panels[c]))}},select:function(b){if(typeof b=="string"){b=this.anchors.index(this.anchors.filter("[href$="+b+"]"))}else{if(b===null){b=-1}}if(b==-1&&this.options.collapsible){b=this.options.selected}this.anchors.eq(b).trigger(this.options.event+".tabs")},load:function(e){var c=this,g=this.options,b=this.anchors.eq(e)[0],d=a.data(b,"load.tabs");this.abort();if(!d||this.element.queue("tabs").length!==0&&a.data(b,"cache.tabs")){this.element.dequeue("tabs");return}this.lis.eq(e).addClass("ui-state-processing");if(g.spinner){var f=a("span",b);f.data("label.tabs",f.html()).html(g.spinner)}this.xhr=a.ajax(a.extend({},g.ajaxOptions,{url:d,success:function(i,h){a(c._sanitizeSelector(b.hash)).html(i);c._cleanup();if(g.cache){a.data(b,"cache.tabs",true)}c._trigger("load",null,c._ui(c.anchors[e],c.panels[e]));try{g.ajaxOptions.success(i,h)}catch(j){}c.element.dequeue("tabs")}}))},abort:function(){this.element.queue([]);this.panels.stop(false,true);if(this.xhr){this.xhr.abort();delete this.xhr}this._cleanup()},url:function(c,b){this.anchors.eq(c).removeData("cache.tabs").data("load.tabs",b)},length:function(){return this.anchors.length}});a.extend(a.ui.tabs,{version:"1.7.2",getter:"length",defaults:{ajaxOptions:null,cache:false,cookie:null,collapsible:false,disabled:[],event:"click",fx:null,idPrefix:"ui-tabs-",panelTemplate:"
                ",spinner:"Loading…",tabTemplate:'
              • #{label}
              • '}});a.extend(a.ui.tabs.prototype,{rotation:null,rotate:function(d,f){var b=this,g=this.options;var c=b._rotate||(b._rotate=function(h){clearTimeout(b.rotation);b.rotation=setTimeout(function(){var i=g.selected;b.select(++i
                ').appendTo(this.element);this._refreshValue()},destroy:function(){this.element.removeClass("ui-progressbar ui-widget ui-widget-content ui-corner-all").removeAttr("role").removeAttr("aria-valuemin").removeAttr("aria-valuemax").removeAttr("aria-valuenow").removeData("progressbar").unbind(".progressbar");this.valueDiv.remove();a.widget.prototype.destroy.apply(this,arguments)},value:function(b){if(b===undefined){return this._value()}this._setData("value",b);return this},_setData:function(b,c){switch(b){case"value":this.options.value=c;this._refreshValue();this._trigger("change",null,{});break}a.widget.prototype._setData.apply(this,arguments)},_value:function(){var b=this.options.value;if(bthis._valueMax()){b=this._valueMax()}return b},_valueMin:function(){var b=0;return b},_valueMax:function(){var b=100;return b},_refreshValue:function(){var b=this.value();this.valueDiv[b==this._valueMax()?"addClass":"removeClass"]("ui-corner-right");this.valueDiv.width(b+"%");this.element.attr("aria-valuenow",b)}});a.extend(a.ui.progressbar,{version:"1.7.2",defaults:{value:0}})})(jQuery);;/* - * jQuery UI Effects 1.7.2 - * - * Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT (MIT-LICENSE.txt) - * and GPL (GPL-LICENSE.txt) licenses. - * - * http://docs.jquery.com/UI/Effects/ - */ -jQuery.effects||(function(d){d.effects={version:"1.7.2",save:function(g,h){for(var f=0;f');var j=f.parent();if(f.css("position")=="static"){j.css({position:"relative"});f.css({position:"relative"})}else{var i=f.css("top");if(isNaN(parseInt(i,10))){i="auto"}var h=f.css("left");if(isNaN(parseInt(h,10))){h="auto"}j.css({position:f.css("position"),top:i,left:h,zIndex:f.css("z-index")}).show();f.css({position:"relative",top:0,left:0})}j.css(g);return j},removeWrapper:function(f){if(f.parent().is(".ui-effects-wrapper")){return f.parent().replaceWith(f)}return f},setTransition:function(g,i,f,h){h=h||{};d.each(i,function(k,j){unit=g.cssUnit(j);if(unit[0]>0){h[j]=unit[0]*f+unit[1]}});return h},animateClass:function(h,i,k,j){var f=(typeof k=="function"?k:(j?j:null));var g=(typeof k=="string"?k:null);return this.each(function(){var q={};var o=d(this);var p=o.attr("style")||"";if(typeof p=="object"){p=p.cssText}if(h.toggle){o.hasClass(h.toggle)?h.remove=h.toggle:h.add=h.toggle}var l=d.extend({},(document.defaultView?document.defaultView.getComputedStyle(this,null):this.currentStyle));if(h.add){o.addClass(h.add)}if(h.remove){o.removeClass(h.remove)}var m=d.extend({},(document.defaultView?document.defaultView.getComputedStyle(this,null):this.currentStyle));if(h.add){o.removeClass(h.add)}if(h.remove){o.addClass(h.remove)}for(var r in m){if(typeof m[r]!="function"&&m[r]&&r.indexOf("Moz")==-1&&r.indexOf("length")==-1&&m[r]!=l[r]&&(r.match(/color/i)||(!r.match(/color/i)&&!isNaN(parseInt(m[r],10))))&&(l.position!="static"||(l.position=="static"&&!r.match(/left|top|bottom|right/)))){q[r]=m[r]}}o.animate(q,i,g,function(){if(typeof d(this).attr("style")=="object"){d(this).attr("style")["cssText"]="";d(this).attr("style")["cssText"]=p}else{d(this).attr("style",p)}if(h.add){d(this).addClass(h.add)}if(h.remove){d(this).removeClass(h.remove)}if(f){f.apply(this,arguments)}})})}};function c(g,f){var i=g[1]&&g[1].constructor==Object?g[1]:{};if(f){i.mode=f}var h=g[1]&&g[1].constructor!=Object?g[1]:(i.duration?i.duration:g[2]);h=d.fx.off?0:typeof h==="number"?h:d.fx.speeds[h]||d.fx.speeds._default;var j=i.callback||(d.isFunction(g[1])&&g[1])||(d.isFunction(g[2])&&g[2])||(d.isFunction(g[3])&&g[3]);return[g[0],i,h,j]}d.fn.extend({_show:d.fn.show,_hide:d.fn.hide,__toggle:d.fn.toggle,_addClass:d.fn.addClass,_removeClass:d.fn.removeClass,_toggleClass:d.fn.toggleClass,effect:function(g,f,h,i){return d.effects[g]?d.effects[g].call(this,{method:g,options:f||{},duration:h,callback:i}):null},show:function(){if(!arguments[0]||(arguments[0].constructor==Number||(/(slow|normal|fast)/).test(arguments[0]))){return this._show.apply(this,arguments)}else{return this.effect.apply(this,c(arguments,"show"))}},hide:function(){if(!arguments[0]||(arguments[0].constructor==Number||(/(slow|normal|fast)/).test(arguments[0]))){return this._hide.apply(this,arguments)}else{return this.effect.apply(this,c(arguments,"hide"))}},toggle:function(){if(!arguments[0]||(arguments[0].constructor==Number||(/(slow|normal|fast)/).test(arguments[0]))||(d.isFunction(arguments[0])||typeof arguments[0]=="boolean")){return this.__toggle.apply(this,arguments)}else{return this.effect.apply(this,c(arguments,"toggle"))}},addClass:function(g,f,i,h){return f?d.effects.animateClass.apply(this,[{add:g},f,i,h]):this._addClass(g)},removeClass:function(g,f,i,h){return f?d.effects.animateClass.apply(this,[{remove:g},f,i,h]):this._removeClass(g)},toggleClass:function(g,f,i,h){return((typeof f!=="boolean")&&f)?d.effects.animateClass.apply(this,[{toggle:g},f,i,h]):this._toggleClass(g,f)},morph:function(f,h,g,j,i){return d.effects.animateClass.apply(this,[{add:h,remove:f},g,j,i])},switchClass:function(){return this.morph.apply(this,arguments)},cssUnit:function(f){var g=this.css(f),h=[];d.each(["em","px","%","pt"],function(j,k){if(g.indexOf(k)>0){h=[parseFloat(g),k]}});return h}});d.each(["backgroundColor","borderBottomColor","borderLeftColor","borderRightColor","borderTopColor","color","outlineColor"],function(g,f){d.fx.step[f]=function(h){if(h.state==0){h.start=e(h.elem,f);h.end=b(h.end)}h.elem.style[f]="rgb("+[Math.max(Math.min(parseInt((h.pos*(h.end[0]-h.start[0]))+h.start[0],10),255),0),Math.max(Math.min(parseInt((h.pos*(h.end[1]-h.start[1]))+h.start[1],10),255),0),Math.max(Math.min(parseInt((h.pos*(h.end[2]-h.start[2]))+h.start[2],10),255),0)].join(",")+")"}});function b(g){var f;if(g&&g.constructor==Array&&g.length==3){return g}if(f=/rgb\(\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*\)/.exec(g)){return[parseInt(f[1],10),parseInt(f[2],10),parseInt(f[3],10)]}if(f=/rgb\(\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*\)/.exec(g)){return[parseFloat(f[1])*2.55,parseFloat(f[2])*2.55,parseFloat(f[3])*2.55]}if(f=/#([a-fA-F0-9]{2})([a-fA-F0-9]{2})([a-fA-F0-9]{2})/.exec(g)){return[parseInt(f[1],16),parseInt(f[2],16),parseInt(f[3],16)]}if(f=/#([a-fA-F0-9])([a-fA-F0-9])([a-fA-F0-9])/.exec(g)){return[parseInt(f[1]+f[1],16),parseInt(f[2]+f[2],16),parseInt(f[3]+f[3],16)]}if(f=/rgba\(0, 0, 0, 0\)/.exec(g)){return a.transparent}return a[d.trim(g).toLowerCase()]}function e(h,f){var g;do{g=d.curCSS(h,f);if(g!=""&&g!="transparent"||d.nodeName(h,"body")){break}f="backgroundColor"}while(h=h.parentNode);return b(g)}var a={aqua:[0,255,255],azure:[240,255,255],beige:[245,245,220],black:[0,0,0],blue:[0,0,255],brown:[165,42,42],cyan:[0,255,255],darkblue:[0,0,139],darkcyan:[0,139,139],darkgrey:[169,169,169],darkgreen:[0,100,0],darkkhaki:[189,183,107],darkmagenta:[139,0,139],darkolivegreen:[85,107,47],darkorange:[255,140,0],darkorchid:[153,50,204],darkred:[139,0,0],darksalmon:[233,150,122],darkviolet:[148,0,211],fuchsia:[255,0,255],gold:[255,215,0],green:[0,128,0],indigo:[75,0,130],khaki:[240,230,140],lightblue:[173,216,230],lightcyan:[224,255,255],lightgreen:[144,238,144],lightgrey:[211,211,211],lightpink:[255,182,193],lightyellow:[255,255,224],lime:[0,255,0],magenta:[255,0,255],maroon:[128,0,0],navy:[0,0,128],olive:[128,128,0],orange:[255,165,0],pink:[255,192,203],purple:[128,0,128],violet:[128,0,128],red:[255,0,0],silver:[192,192,192],white:[255,255,255],yellow:[255,255,0],transparent:[255,255,255]};d.easing.jswing=d.easing.swing;d.extend(d.easing,{def:"easeOutQuad",swing:function(g,h,f,j,i){return d.easing[d.easing.def](g,h,f,j,i)},easeInQuad:function(g,h,f,j,i){return j*(h/=i)*h+f},easeOutQuad:function(g,h,f,j,i){return -j*(h/=i)*(h-2)+f},easeInOutQuad:function(g,h,f,j,i){if((h/=i/2)<1){return j/2*h*h+f}return -j/2*((--h)*(h-2)-1)+f},easeInCubic:function(g,h,f,j,i){return j*(h/=i)*h*h+f},easeOutCubic:function(g,h,f,j,i){return j*((h=h/i-1)*h*h+1)+f},easeInOutCubic:function(g,h,f,j,i){if((h/=i/2)<1){return j/2*h*h*h+f}return j/2*((h-=2)*h*h+2)+f},easeInQuart:function(g,h,f,j,i){return j*(h/=i)*h*h*h+f},easeOutQuart:function(g,h,f,j,i){return -j*((h=h/i-1)*h*h*h-1)+f},easeInOutQuart:function(g,h,f,j,i){if((h/=i/2)<1){return j/2*h*h*h*h+f}return -j/2*((h-=2)*h*h*h-2)+f},easeInQuint:function(g,h,f,j,i){return j*(h/=i)*h*h*h*h+f},easeOutQuint:function(g,h,f,j,i){return j*((h=h/i-1)*h*h*h*h+1)+f},easeInOutQuint:function(g,h,f,j,i){if((h/=i/2)<1){return j/2*h*h*h*h*h+f}return j/2*((h-=2)*h*h*h*h+2)+f},easeInSine:function(g,h,f,j,i){return -j*Math.cos(h/i*(Math.PI/2))+j+f},easeOutSine:function(g,h,f,j,i){return j*Math.sin(h/i*(Math.PI/2))+f},easeInOutSine:function(g,h,f,j,i){return -j/2*(Math.cos(Math.PI*h/i)-1)+f},easeInExpo:function(g,h,f,j,i){return(h==0)?f:j*Math.pow(2,10*(h/i-1))+f},easeOutExpo:function(g,h,f,j,i){return(h==i)?f+j:j*(-Math.pow(2,-10*h/i)+1)+f},easeInOutExpo:function(g,h,f,j,i){if(h==0){return f}if(h==i){return f+j}if((h/=i/2)<1){return j/2*Math.pow(2,10*(h-1))+f}return j/2*(-Math.pow(2,-10*--h)+2)+f},easeInCirc:function(g,h,f,j,i){return -j*(Math.sqrt(1-(h/=i)*h)-1)+f},easeOutCirc:function(g,h,f,j,i){return j*Math.sqrt(1-(h=h/i-1)*h)+f},easeInOutCirc:function(g,h,f,j,i){if((h/=i/2)<1){return -j/2*(Math.sqrt(1-h*h)-1)+f}return j/2*(Math.sqrt(1-(h-=2)*h)+1)+f},easeInElastic:function(g,i,f,m,l){var j=1.70158;var k=0;var h=m;if(i==0){return f}if((i/=l)==1){return f+m}if(!k){k=l*0.3}if(h').appendTo(document.body).addClass(b.options.className).css({top:d.top,left:d.left,height:f.innerHeight(),width:f.innerWidth(),position:"absolute"}).animate(g,b.duration,b.options.easing,function(){c.remove();(b.callback&&b.callback.apply(f[0],arguments));f.dequeue()})})}})(jQuery);;/* - * jQuery UI Selectable @VERSION - * - * Copyright (c) 2009 AUTHORS.txt (http://ui.jquery.com/about) - * Dual licensed under the MIT (MIT-LICENSE.txt) - * and GPL (GPL-LICENSE.txt) licenses. - * - * http://docs.jquery.com/UI/Selectables - * - * Depends: - * ui.core.js - */ -(function($) { - - $.widget('ui.selectable', $.extend({}, $.ui.mouse, { - - _init: function() { - - var self = this; - this.items = $(this.options.filter, this.element); - this.element.addClass("ui-selectable"); - - //Set the currentFocus to the first item - this.currentFocus = this.items.eq(0); - - //Refresh item positions - this.refresh(); - - //Disable text selection - this.element.disableSelection(); - - //Prepare caret selection - if(this.options.lasso) this._mouseInit(); - - this.element - .bind('mousedown.selectable', function(event) { - - var item = self._targetIsItem(event.target); - if (!item) return; - - // If item is part of current selection and current - // selection is multiple, return and allow mouseup - // to fire (Windows gets this right too, OSX doesn't) - if(self._selection.length > 1 && $(item).hasClass(self.options.selectedClass)) { - return (self._listenForMouseUp = 1); - } - - if(self._trigger('beforeselect', event) === false) - return true; - - self._select(event, item); - self.element[0].focus(); - event.preventDefault(); - - }) - .bind('mouseup.selectable', function(event) { - if(self._listenForMouseUp) { - - self._listenForMouseUp = 0; - var item = self._targetIsItem(event.target); - if (!item) return; - - if(self._trigger('beforeselect', event) === false) - return true; - - self._select(event, item); - self.element[0].focus(); - event.preventDefault(); - } - }) - .bind('focus.selectable', function() { - self.currentFocus.addClass('ui-focused'); - }) - .bind('blur.selectable', function() { - self.currentFocus.removeClass('ui-focused'); - }) - .bind('keydown.selectable', function(event) { - - if(!self.options.keyboard) - return; - - if(self._trigger('beforeselect', event) === false) - return true; - - if(event.keyCode == $.ui.keyCode.DOWN) { - self.options.smart ? self.selectClosest('down', event) : self.selectNext(event); - event.preventDefault(); - } - - if(event.keyCode == $.ui.keyCode.RIGHT) { - self.options.smart ? self.selectClosest('right', event) : self.selectNext(event); - event.preventDefault(); - } - - if(event.keyCode == $.ui.keyCode.UP) { - self.options.smart ? self.selectClosest('up', event) : self.selectPrevious(event); - event.preventDefault(); - } - - if(event.keyCode == $.ui.keyCode.LEFT) { - self.options.smart ? self.selectClosest('left', event) : self.selectPrevious(event); - event.preventDefault(); - } - - if ((event.ctrlKey || event.metaKey) && event.keyCode == $.ui.keyCode.SPACE) { - self._toggleSelection(self.currentFocus, event); - } - - }); - - this.helper = $(document.createElement('div')) - .addClass("ui-selectable-lasso"); - - }, - - selectClosest: function(direction, event) { - - var current = [/(down|right)/.test(direction) ? 10000 : -10000, null], - overlap = 10000, - selfOffset = this.currentFocus.data('selectable-item'); - - $(this.options.filter, this.element).not(this.currentFocus).filter(':visible').each(function() { - - var $this = $(this), - offset = $this.data('selectable-item'), - distance = { - x: Math.abs(selfOffset.left - offset.left) + Math.abs((offset.left+this.offsetWidth) - (selfOffset.left+this.offsetWidth)), - y: Math.abs(selfOffset.top - offset.top) + Math.abs((offset.top+this.offsetHeight) - (selfOffset.top+this.offsetHeight)) - }; - - switch(direction) { - - case 'up': - if((selfOffset.top > offset.top && offset.top >= current[0]) && (offset.top != current[0] || distance.x < overlap)) { - current = [offset.top, $this]; - overlap = distance.x; - } - break; - - case 'down': - if((selfOffset.top < offset.top && offset.top <= current[0]) && (offset.top != current[0] || distance.x < overlap)) { - current = [offset.top, $this]; - overlap = distance.x; - } - break; - - case 'left': - if((selfOffset.left > offset.left && offset.left >= current[0]) && (offset.left != current[0] || distance.y < overlap)) { - current = [offset.left, $this]; - overlap = distance.y; - } - break; - - case 'right': - if((selfOffset.left < offset.left && offset.left <= current[0]) && (offset.left != current[0] || distance.y < overlap)) { - current = [offset.left, $this]; - overlap = distance.y; - } - break; - - } - - }); - - return current[1] ? this._select(event, current[1]) : false; - - }, - - destroy: function() { - this.element - .removeClass("ui-selectable ui-selectable-disabled") - .removeData("selectable") - .unbind(".selectable"); - this._mouseDestroy(); - }, - - _mouseCapture: function(event) { - //If the item we start dragging on is a selectable, we bail (if keyboard is used) - this.clickedOnItem = this._targetIsItem(event.target); - return !this.options.keyboard || !this.clickedOnItem; - }, - - _mouseStart: function(event) { - - var self = this, o = this.options; - this.opos = [event.pageX, event.pageY]; - - if (o.disabled) - return; - - //Cache positions - this.refresh(); - - //Trigger start event - this._trigger("start", event, this._uiHash()); - - // append and position helper (lasso) - $('body').append(this.helper); - this.helper.css({ - zIndex: 100, - position: "absolute", - left: event.clientX, - top: event.clientY, - width: 0, - height: 0 - }); - - //Tell the intersection that some start selected - this.items.filter('.'+this.options.selectedClass).each(function() { - if(event.metaKey) { - if(this != self.clickedOnItem) $.data(this, "selectable-item").startSelected = true; - } else self._removeFromSelection($(this), event); - }); - - }, - - _mouseDrag: function(event) { - - var self = this, o = this.options; - - if (o.disabled) - return; - - //Do the lasso magic - var x1 = this.opos[0], y1 = this.opos[1], x2 = event.pageX, y2 = event.pageY; - if (x1 > x2) { var tmp = x2; x2 = x1; x1 = tmp; } - if (y1 > y2) { var tmp = y2; y2 = y1; y1 = tmp; } - this.helper.css({left: x1, top: y1, width: x2-x1, height: y2-y1}); - - //Loop through all items and check overlaps - this.items.each(function() { - - var item = $.data(this, "selectable-item"); - - //prevent helper from being selected if appendTo: selectable - if (!item || item.element == self.element[0]) - return; - - var hit = false; - if (o.lasso && o.lasso.tolerance == 'touch') { - hit = ( !(item.left > x2 || item.right < x1 || item.top > y2 || item.bottom < y1) ); - } else if (o.lasso && o.lasso.tolerance == 'fit') { - hit = (item.left > x1 && item.right < x2 && item.top > y1 && item.bottom < y2); - } - - hit ? - item.startSelected ? self._removeFromSelection($(this), event) : self._addToSelection($(this), event) - : !item.startSelected ? self._removeFromSelection($(this), event) : self._addToSelection($(this), event); - - }); - - return false; - - }, - - _mouseStop: function(event) { - this._trigger("stop", event, this._uiHash()); - this.helper.remove(); - return false; - }, - - _targetIsItem: function(item) { - var found = $(item).parents().andSelf().filter(':data(selectable-item)'); - return found.length && found; - }, - - _selection: [], - - _clearSelection: function(triggerEvent) { - - var triggerItems = []; - - for (var i = this._selection.length - 1; i >= 0; i--){ - if(triggerEvent && this._selection[i].data('selectable-item').selected) triggerItems.push(this._selection[i]); - this._selection[i].removeClass(this.options.selectedClass); - this._selection[i].data('selectable-item').selected = false; - }; - - this._selection = []; - if(triggerEvent) this._trigger('unselect', triggerEvent, this._uiHash($($.map(triggerItems, function(i) { return i[0]; })), 'removed')); - - }, - - _toggleSelection: function(item, event) { - item.data('selectable-item').selected ? this._removeFromSelection(item, event) : this._addToSelection(item); - }, - - _addToSelection: function(item, triggerEvent) { - - if (item.data('selectable-item').selected) - return null; - - this._selection.push(item); - this.latestSelection = item; - item.addClass(this.options.selectedClass); - item.data('selectable-item').selected = true; - - if(triggerEvent) { - this._trigger('select', triggerEvent, $.extend({ lasso: true }, this._uiHash(item))); - } - - return item; - - }, - - _removeFromSelection: function(item, triggerEvent) { - - for (var i=0; i < this._selection.length; i++) { - if (this._selection[i][0] == item[0]) { - this._selection[i].removeClass(this.options.selectedClass); - this._selection[i].data('selectable-item').selected = false; - this._selection.splice(i,1); - if(triggerEvent) this._trigger('unselect', triggerEvent, this._uiHash($(item), 'removed')); - break; - } - }; - - }, - - _updateSelectionMouse: function(event) { - - var newlySelected = []; - - if (event.shiftKey && this.options.multiple) { - - //Clear the previous selection to make room for a shift selection - this._clearSelection(event); - - var index = this.items.index(this.latestWithoutModifier[0]) > this.items.index(this.currentFocus[0]) ? -1 : 1; - var i = this.latestWithoutModifier.data('selectable-item').selected ? this.items.eq(this.items.index(this.latestWithoutModifier[0])+index) : this.latestWithoutModifier; - while(i.length && i[0] != this.currentFocus[0]) { - i[0] == this.previousFocus[0] ? this._addToSelection(i) : newlySelected.push(this._addToSelection(i)); - i = this.items.eq(this.items.index(i[0])+index); - } - - //Readd the item with the current focus - newlySelected.push(this._addToSelection(this.currentFocus)); - - } else { - - if (event.metaKey) { - this._toggleSelection(this.currentFocus, event); - } else { - this._clearSelection(event); - newlySelected.push(this._addToSelection(this.currentFocus)); - this.latestWithoutModifier = this.currentFocus; - } - - } - - return $($.map(newlySelected, function(i) { return i[0]; })); - - }, - - _updateSelection: function(event, index) { - - var newlySelected = []; - - if (event.shiftKey && this.options.multiple) { - - if (this.currentFocus.data('selectable-item').selected) { - this._removeFromSelection(this.previousFocus, event); - } else { - - var index2 = this.items.index(this.latestSelection[0]) > this.items.index(this.currentFocus[0]) ? 1 : -1; - if (!this.previousFocus.data('selectable-item').selected) { - var i = index == index2 ? this.items.eq(this.items.index(this.previousFocus[0])+index2) : this.previousFocus; - while(i.length && !i.data('selectable-item').selected) { - newlySelected.push(this._addToSelection(i)); - i = this.items.eq(this.items.index(i[0])+index2); - } - } - - newlySelected.push(this._addToSelection(this.currentFocus)); - - } - - } else { - - //If the CTRL or Apple/Win key is pressed, only set focus - if (event.metaKey) - return; - - this._clearSelection(event); - newlySelected.push(this._addToSelection(this.currentFocus)); - this.latestWithoutModifier = this.currentFocus; - - } - - return $($.map(newlySelected, function(i) { return i[0]; })); - - }, - - _select: function(event, item) { - - //Set the current selection to the previous/next item - this.previousFocus = this.currentFocus; - this.currentFocus = $(item); - - this.previousFocus.removeClass('ui-focused'); - this.currentFocus.addClass('ui-focused'); - - //Set and update the selection - var newlySelected = this._updateSelectionMouse(event); - - //Trigger select event - if(newlySelected && newlySelected.length) this._trigger('select', event, this._uiHash(newlySelected, 'added')); - - }, - - _selectAdjacent: function(event, index) { - - var item = this.items.eq(this.items.index(this.currentFocus[0]) + index); - - //Bail if there's no previous/next item - if (!item.length) return; - - //Set the current selection to the previous/next item - this.previousFocus = this.currentFocus; - this.currentFocus = item; - - this.previousFocus.removeClass('ui-focused'); - this.currentFocus.addClass('ui-focused'); - - //Set and update the selection - var newlySelected = this._updateSelection(event, index); - - //Trigger select event - if(newlySelected && newlySelected.length) this._trigger('select', event, this._uiHash(newlySelected, 'added')); - - }, - - selectPrevious: function(event) { - this._selectAdjacent(event, -1); - }, - - selectNext: function(event) { - this._selectAdjacent(event, 1); - }, - - refresh: function() { - - var o = this.options; - this.items = $(o.filter, this.element); - this.items.each(function() { - var $this = $(this); - var pos = $this.offset(); - $.data(this, "selectable-item", { - left: pos.left, - top: pos.top, - right: pos.left + $this.width(), - bottom: pos.top + $this.height(), - startSelected: false, - selected: $this.hasClass(o.selectedClass) - }); - }); - - }, - - select: function(item) { - //TODO - }, - - deselect: function(item) { - if(!item) this._clearSelection(true); - //TODO: Deselect single elements - }, - - _uiHash: function(items, specialKey) { - var uiHash = { - previousFocus: this.previousFocus, - currentFocus: this.currentFocus, - selection: $($.map(this._selection, function(i) { return i[0]; })) - }; - if(specialKey) uiHash[specialKey] = items; - return uiHash; - } - - })); - - $.extend($.ui.selectable, { - defaults: { - - //TODO: Figure out how to move these defaults out - cancel: ":input,option", - delay: 0, - distance: 1, - appendTo: 'body', - - multiple: true, - smart: true, - filter: '> *', - - keyboard: true, - lasso: { - cancel: ":input,option", - delay: 0, - distance: 1, - tolerance: 'touch', - appendTo: 'body' - }, - - //Should we really delete that? - selectedClass: 'ui-state-selected' - } - }); - -})(jQuery); +;jQuery.ui||(function($){var _remove=$.fn.remove,isFF2=$.browser.mozilla&&(parseFloat($.browser.version)<1.9);$.ui={version:"1.7.2",plugin:{add:function(module,option,set){var proto=$.ui[module].prototype;for(var i in set){proto.plugins[i]=proto.plugins[i]||[];proto.plugins[i].push([option,set[i]]);}},call:function(instance,name,args){var set=instance.plugins[name];if(!set||!instance.element[0].parentNode){return;} +for(var i=0;i0){return true;} +el[scroll]=1;has=(el[scroll]>0);el[scroll]=0;return has;},isOverAxis:function(x,reference,size){return(x>reference)&&(x<(reference+size));},isOver:function(y,x,top,left,height,width){return $.ui.isOverAxis(y,top,height)&&$.ui.isOverAxis(x,left,width);},keyCode:{BACKSPACE:8,CAPS_LOCK:20,COMMA:188,CONTROL:17,DELETE:46,DOWN:40,END:35,ENTER:13,ESCAPE:27,HOME:36,INSERT:45,LEFT:37,NUMPAD_ADD:107,NUMPAD_DECIMAL:110,NUMPAD_DIVIDE:111,NUMPAD_ENTER:108,NUMPAD_MULTIPLY:106,NUMPAD_SUBTRACT:109,PAGE_DOWN:34,PAGE_UP:33,PERIOD:190,RIGHT:39,SHIFT:16,SPACE:32,TAB:9,UP:38}};if(isFF2){var attr=$.attr,removeAttr=$.fn.removeAttr,ariaNS="http://www.w3.org/2005/07/aaa",ariaState=/^aria-/,ariaRole=/^wairole:/;$.attr=function(elem,name,value){var set=value!==undefined;return(name=='role'?(set?attr.call(this,elem,name,"wairole:"+value):(attr.apply(this,arguments)||"").replace(ariaRole,"")):(ariaState.test(name)?(set?elem.setAttributeNS(ariaNS,name.replace(ariaState,"aaa:"),value):attr.call(this,elem,name.replace(ariaState,"aaa:"))):attr.apply(this,arguments)));};$.fn.removeAttr=function(name){return(ariaState.test(name)?this.each(function(){this.removeAttributeNS(ariaNS,name.replace(ariaState,""));}):removeAttr.call(this,name));};} +$.fn.extend({remove:function(){$("*",this).add(this).each(function(){$(this).triggerHandler("remove");});return _remove.apply(this,arguments);},enableSelection:function(){return this.attr('unselectable','off').css('MozUserSelect','').unbind('selectstart.ui');},disableSelection:function(){return this.attr('unselectable','on').css('MozUserSelect','none').bind('selectstart.ui',function(){return false;});},scrollParent:function(){var scrollParent;if(($.browser.msie&&(/(static|relative)/).test(this.css('position')))||(/absolute/).test(this.css('position'))){scrollParent=this.parents().filter(function(){return(/(relative|absolute|fixed)/).test($.curCSS(this,'position',1))&&(/(auto|scroll)/).test($.curCSS(this,'overflow',1)+$.curCSS(this,'overflow-y',1)+$.curCSS(this,'overflow-x',1));}).eq(0);}else{scrollParent=this.parents().filter(function(){return(/(auto|scroll)/).test($.curCSS(this,'overflow',1)+$.curCSS(this,'overflow-y',1)+$.curCSS(this,'overflow-x',1));}).eq(0);} +return(/fixed/).test(this.css('position'))||!scrollParent.length?$(document):scrollParent;}});$.extend($.expr[':'],{data:function(elem,i,match){return!!$.data(elem,match[3]);},focusable:function(element){var nodeName=element.nodeName.toLowerCase(),tabIndex=$.attr(element,'tabindex');return(/input|select|textarea|button|object/.test(nodeName)?!element.disabled:'a'==nodeName||'area'==nodeName?element.href||!isNaN(tabIndex):!isNaN(tabIndex))&&!$(element)['area'==nodeName?'parents':'closest'](':hidden').length;},tabbable:function(element){var tabIndex=$.attr(element,'tabindex');return(isNaN(tabIndex)||tabIndex>=0)&&$(element).is(':focusable');}});function getter(namespace,plugin,method,args){function getMethods(type){var methods=$[namespace][plugin][type]||[];return(typeof methods=='string'?methods.split(/,?\s+/):methods);} +var methods=getMethods('getter');if(args.length==1&&typeof args[0]=='string'){methods=methods.concat(getMethods('getterSetter'));} +return($.inArray(method,methods)!=-1);} +$.widget=function(name,prototype){var namespace=name.split(".")[0];name=name.split(".")[1];$.fn[name]=function(options){var isMethodCall=(typeof options=='string'),args=Array.prototype.slice.call(arguments,1);if(isMethodCall&&options.substring(0,1)=='_'){return this;} +if(isMethodCall&&getter(namespace,name,options,args)){var instance=$.data(this[0],name);return(instance?instance[options].apply(instance,args):undefined);} +return this.each(function(){var instance=$.data(this,name);(!instance&&!isMethodCall&&$.data(this,name,new $[namespace][name](this,options))._init());(instance&&isMethodCall&&$.isFunction(instance[options])&&instance[options].apply(instance,args));});};$[namespace]=$[namespace]||{};$[namespace][name]=function(element,options){var self=this;this.namespace=namespace;this.widgetName=name;this.widgetEventPrefix=$[namespace][name].eventPrefix||name;this.widgetBaseClass=namespace+'-'+name;this.options=$.extend({},$.widget.defaults,$[namespace][name].defaults,$.metadata&&$.metadata.get(element)[name],options);this.element=$(element).bind('setData.'+name,function(event,key,value){if(event.target==element){return self._setData(key,value);}}).bind('getData.'+name,function(event,key){if(event.target==element){return self._getData(key);}}).bind('remove',function(){return self.destroy();});};$[namespace][name].prototype=$.extend({},$.widget.prototype,prototype);$[namespace][name].getterSetter='option';};$.widget.prototype={_init:function(){},destroy:function(){this.element.removeData(this.widgetName).removeClass(this.widgetBaseClass+'-disabled'+' '+this.namespace+'-state-disabled').removeAttr('aria-disabled');},option:function(key,value){var options=key,self=this;if(typeof key=="string"){if(value===undefined){return this._getData(key);} +options={};options[key]=value;} +$.each(options,function(key,value){self._setData(key,value);});},_getData:function(key){return this.options[key];},_setData:function(key,value){this.options[key]=value;if(key=='disabled'){this.element +[value?'addClass':'removeClass'](this.widgetBaseClass+'-disabled'+' '+ +this.namespace+'-state-disabled').attr("aria-disabled",value);}},enable:function(){this._setData('disabled',false);},disable:function(){this._setData('disabled',true);},_trigger:function(type,event,data){var callback=this.options[type],eventName=(type==this.widgetEventPrefix?type:this.widgetEventPrefix+type);event=$.Event(event);event.type=eventName;if(event.originalEvent){for(var i=$.event.props.length,prop;i;){prop=$.event.props[--i];event[prop]=event.originalEvent[prop];}} +this.element.trigger(event,data);return!($.isFunction(callback)&&callback.call(this.element[0],event,data)===false||event.isDefaultPrevented());}};$.widget.defaults={disabled:false};$.ui.mouse={_mouseInit:function(){var self=this;this.element.bind('mousedown.'+this.widgetName,function(event){return self._mouseDown(event);}).bind('click.'+this.widgetName,function(event){if(self._preventClickEvent){self._preventClickEvent=false;event.stopImmediatePropagation();return false;}});if($.browser.msie){this._mouseUnselectable=this.element.attr('unselectable');this.element.attr('unselectable','on');} +this.started=false;},_mouseDestroy:function(){this.element.unbind('.'+this.widgetName);($.browser.msie&&this.element.attr('unselectable',this._mouseUnselectable));},_mouseDown:function(event){event.originalEvent=event.originalEvent||{};if(event.originalEvent.mouseHandled){return;} +(this._mouseStarted&&this._mouseUp(event));this._mouseDownEvent=event;var self=this,btnIsLeft=(event.which==1),elIsCancel=(typeof this.options.cancel=="string"?$(event.target).parents().add(event.target).filter(this.options.cancel).length:false);if(!btnIsLeft||elIsCancel||!this._mouseCapture(event)){return true;} +this.mouseDelayMet=!this.options.delay;if(!this.mouseDelayMet){this._mouseDelayTimer=setTimeout(function(){self.mouseDelayMet=true;},this.options.delay);} +if(this._mouseDistanceMet(event)&&this._mouseDelayMet(event)){this._mouseStarted=(this._mouseStart(event)!==false);if(!this._mouseStarted){event.preventDefault();return true;}} +this._mouseMoveDelegate=function(event){return self._mouseMove(event);};this._mouseUpDelegate=function(event){return self._mouseUp(event);};$(document).bind('mousemove.'+this.widgetName,this._mouseMoveDelegate).bind('mouseup.'+this.widgetName,this._mouseUpDelegate);($.browser.safari||event.preventDefault());event.originalEvent.mouseHandled=true;return true;},_mouseMove:function(event){if($.browser.msie&&!event.button){return this._mouseUp(event);} +if(this._mouseStarted){this._mouseDrag(event);return event.preventDefault();} +if(this._mouseDistanceMet(event)&&this._mouseDelayMet(event)){this._mouseStarted=(this._mouseStart(this._mouseDownEvent,event)!==false);(this._mouseStarted?this._mouseDrag(event):this._mouseUp(event));} +return!this._mouseStarted;},_mouseUp:function(event){$(document).unbind('mousemove.'+this.widgetName,this._mouseMoveDelegate).unbind('mouseup.'+this.widgetName,this._mouseUpDelegate);if(this._mouseStarted){this._mouseStarted=false;this._preventClickEvent=(event.target==this._mouseDownEvent.target);this._mouseStop(event);} +return false;},_mouseDistanceMet:function(event){return(Math.max(Math.abs(this._mouseDownEvent.pageX-event.pageX),Math.abs(this._mouseDownEvent.pageY-event.pageY))>=this.options.distance);},_mouseDelayMet:function(event){return this.mouseDelayMet;},_mouseStart:function(event){},_mouseDrag:function(event){},_mouseStop:function(event){},_mouseCapture:function(event){return true;}};$.ui.mouse.defaults={cancel:null,distance:1,delay:0};})(jQuery);(function($){$.widget("ui.draggable",$.extend({},$.ui.mouse,{_init:function(){if(this.options.helper=='original'&&!(/^(?:r|a|f)/).test(this.element.css("position"))) +this.element[0].style.position='relative';(this.options.addClasses&&this.element.addClass("ui-draggable"));(this.options.disabled&&this.element.addClass("ui-draggable-disabled"));this._mouseInit();},destroy:function(){if(!this.element.data('draggable'))return;this.element.removeData("draggable").unbind(".draggable").removeClass("ui-draggable" ++" ui-draggable-dragging" ++" ui-draggable-disabled");this._mouseDestroy();},_mouseCapture:function(event){var o=this.options;if(this.helper||o.disabled||$(event.target).is('.ui-resizable-handle')) +return false;this.handle=this._getHandle(event);if(!this.handle) +return false;return true;},_mouseStart:function(event){var o=this.options;this.helper=this._createHelper(event);this._cacheHelperProportions();if($.ui.ddmanager) +$.ui.ddmanager.current=this;this._cacheMargins();this.cssPosition=this.helper.css("position");this.scrollParent=this.helper.scrollParent();this.offset=this.element.offset();this.offset={top:this.offset.top-this.margins.top,left:this.offset.left-this.margins.left};$.extend(this.offset,{click:{left:event.pageX-this.offset.left,top:event.pageY-this.offset.top},parent:this._getParentOffset(),relative:this._getRelativeOffset()});this.originalPosition=this._generatePosition(event);this.originalPageX=event.pageX;this.originalPageY=event.pageY;if(o.cursorAt) +this._adjustOffsetFromHelper(o.cursorAt);if(o.containment) +this._setContainment();this._trigger("start",event);this._cacheHelperProportions();if($.ui.ddmanager&&!o.dropBehaviour) +$.ui.ddmanager.prepareOffsets(this,event);this.helper.addClass("ui-draggable-dragging");this._mouseDrag(event,true);return true;},_mouseDrag:function(event,noPropagation){this.position=this._generatePosition(event);this.positionAbs=this._convertPositionTo("absolute");if(!noPropagation){var ui=this._uiHash();this._trigger('drag',event,ui);this.position=ui.position;} +if(!this.options.axis||this.options.axis!="y")this.helper[0].style.left=this.position.left+'px';if(!this.options.axis||this.options.axis!="x")this.helper[0].style.top=this.position.top+'px';if($.ui.ddmanager)$.ui.ddmanager.drag(this,event);return false;},_mouseStop:function(event){var dropped=false;if($.ui.ddmanager&&!this.options.dropBehaviour) +dropped=$.ui.ddmanager.drop(this,event);if(this.dropped){dropped=this.dropped;this.dropped=false;} +if((this.options.revert=="invalid"&&!dropped)||(this.options.revert=="valid"&&dropped)||this.options.revert===true||($.isFunction(this.options.revert)&&this.options.revert.call(this.element,dropped))){var self=this;$(this.helper).animate(this.originalPosition,parseInt(this.options.revertDuration,10),function(){self._trigger("stop",event);self._clear();});}else{this._trigger("stop",event);this._clear();} +return false;},_getHandle:function(event){var handle=!this.options.handle||!$(this.options.handle,this.element).length?true:false;$(this.options.handle,this.element).find("*").andSelf().each(function(){if(this==event.target)handle=true;});return handle;},_createHelper:function(event){var o=this.options;var helper=$.isFunction(o.helper)?$(o.helper.apply(this.element[0],[event])):(o.helper=='clone'?this.element.clone():this.element);if(!helper.parents('body').length) +helper.appendTo((o.appendTo=='parent'?this.element[0].parentNode:o.appendTo));if(helper[0]!=this.element[0]&&!(/(fixed|absolute)/).test(helper.css("position"))) +helper.css("position","absolute");return helper;},_adjustOffsetFromHelper:function(obj){if(obj.left!=undefined)this.offset.click.left=obj.left+this.margins.left;if(obj.right!=undefined)this.offset.click.left=this.helperProportions.width-obj.right+this.margins.left;if(obj.top!=undefined)this.offset.click.top=obj.top+this.margins.top;if(obj.bottom!=undefined)this.offset.click.top=this.helperProportions.height-obj.bottom+this.margins.top;},_getParentOffset:function(){this.offsetParent=this.helper.offsetParent();var po=this.offsetParent.offset();if(this.cssPosition=='absolute'&&this.scrollParent[0]!=document&&$.ui.contains(this.scrollParent[0],this.offsetParent[0])){po.left+=this.scrollParent.scrollLeft();po.top+=this.scrollParent.scrollTop();} +if((this.offsetParent[0]==document.body)||(this.offsetParent[0].tagName&&this.offsetParent[0].tagName.toLowerCase()=='html'&&$.browser.msie)) +po={top:0,left:0};return{top:po.top+(parseInt(this.offsetParent.css("borderTopWidth"),10)||0),left:po.left+(parseInt(this.offsetParent.css("borderLeftWidth"),10)||0)};},_getRelativeOffset:function(){if(this.cssPosition=="relative"){var p=this.element.position();return{top:p.top-(parseInt(this.helper.css("top"),10)||0)+this.scrollParent.scrollTop(),left:p.left-(parseInt(this.helper.css("left"),10)||0)+this.scrollParent.scrollLeft()};}else{return{top:0,left:0};}},_cacheMargins:function(){this.margins={left:(parseInt(this.element.css("marginLeft"),10)||0),top:(parseInt(this.element.css("marginTop"),10)||0)};},_cacheHelperProportions:function(){this.helperProportions={width:this.helper.outerWidth(),height:this.helper.outerHeight()};},_setContainment:function(){var o=this.options;if(o.containment=='parent')o.containment=this.helper[0].parentNode;if(o.containment=='document'||o.containment=='window')this.containment=[0-this.offset.relative.left-this.offset.parent.left,0-this.offset.relative.top-this.offset.parent.top,$(o.containment=='document'?document:window).width()-this.helperProportions.width-this.margins.left,($(o.containment=='document'?document:window).height()||document.body.parentNode.scrollHeight)-this.helperProportions.height-this.margins.top];if(!(/^(document|window|parent)$/).test(o.containment)&&o.containment.constructor!=Array){var ce=$(o.containment)[0];if(!ce)return;var co=$(o.containment).offset();var over=($(ce).css("overflow")!='hidden');this.containment=[co.left+(parseInt($(ce).css("borderLeftWidth"),10)||0)+(parseInt($(ce).css("paddingLeft"),10)||0)-this.margins.left,co.top+(parseInt($(ce).css("borderTopWidth"),10)||0)+(parseInt($(ce).css("paddingTop"),10)||0)-this.margins.top,co.left+(over?Math.max(ce.scrollWidth,ce.offsetWidth):ce.offsetWidth)-(parseInt($(ce).css("borderLeftWidth"),10)||0)-(parseInt($(ce).css("paddingRight"),10)||0)-this.helperProportions.width-this.margins.left,co.top+(over?Math.max(ce.scrollHeight,ce.offsetHeight):ce.offsetHeight)-(parseInt($(ce).css("borderTopWidth"),10)||0)-(parseInt($(ce).css("paddingBottom"),10)||0)-this.helperProportions.height-this.margins.top];}else if(o.containment.constructor==Array){this.containment=o.containment;}},_convertPositionTo:function(d,pos){if(!pos)pos=this.position;var mod=d=="absolute"?1:-1;var o=this.options,scroll=this.cssPosition=='absolute'&&!(this.scrollParent[0]!=document&&$.ui.contains(this.scrollParent[0],this.offsetParent[0]))?this.offsetParent:this.scrollParent,scrollIsRootNode=(/(html|body)/i).test(scroll[0].tagName);return{top:(pos.top ++this.offset.relative.top*mod ++this.offset.parent.top*mod +-($.browser.safari&&this.cssPosition=='fixed'?0:(this.cssPosition=='fixed'?-this.scrollParent.scrollTop():(scrollIsRootNode?0:scroll.scrollTop()))*mod)),left:(pos.left ++this.offset.relative.left*mod ++this.offset.parent.left*mod +-($.browser.safari&&this.cssPosition=='fixed'?0:(this.cssPosition=='fixed'?-this.scrollParent.scrollLeft():scrollIsRootNode?0:scroll.scrollLeft())*mod))};},_generatePosition:function(event){var o=this.options,scroll=this.cssPosition=='absolute'&&!(this.scrollParent[0]!=document&&$.ui.contains(this.scrollParent[0],this.offsetParent[0]))?this.offsetParent:this.scrollParent,scrollIsRootNode=(/(html|body)/i).test(scroll[0].tagName);if(this.cssPosition=='relative'&&!(this.scrollParent[0]!=document&&this.scrollParent[0]!=this.offsetParent[0])){this.offset.relative=this._getRelativeOffset();} +var pageX=event.pageX;var pageY=event.pageY;if(this.originalPosition){if(this.containment){if(event.pageX-this.offset.click.leftthis.containment[2])pageX=this.containment[2]+this.offset.click.left;if(event.pageY-this.offset.click.top>this.containment[3])pageY=this.containment[3]+this.offset.click.top;} +if(o.grid){var top=this.originalPageY+Math.round((pageY-this.originalPageY)/o.grid[1])*o.grid[1];pageY=this.containment?(!(top-this.offset.click.topthis.containment[3])?top:(!(top-this.offset.click.topthis.containment[2])?left:(!(left-this.offset.click.left').css({width:this.offsetWidth+"px",height:this.offsetHeight+"px",position:"absolute",opacity:"0.001",zIndex:1000}).css($(this).offset()).appendTo("body");});},stop:function(event,ui){$("div.ui-draggable-iframeFix").each(function(){this.parentNode.removeChild(this);});}});$.ui.plugin.add("draggable","opacity",{start:function(event,ui){var t=$(ui.helper),o=$(this).data('draggable').options;if(t.css("opacity"))o._opacity=t.css("opacity");t.css('opacity',o.opacity);},stop:function(event,ui){var o=$(this).data('draggable').options;if(o._opacity)$(ui.helper).css('opacity',o._opacity);}});$.ui.plugin.add("draggable","scroll",{start:function(event,ui){var i=$(this).data("draggable");if(i.scrollParent[0]!=document&&i.scrollParent[0].tagName!='HTML')i.overflowOffset=i.scrollParent.offset();},drag:function(event,ui){var i=$(this).data("draggable"),o=i.options,scrolled=false;if(i.scrollParent[0]!=document&&i.scrollParent[0].tagName!='HTML'){if(!o.axis||o.axis!='x'){if((i.overflowOffset.top+i.scrollParent[0].offsetHeight)-event.pageY=0;i--){var l=inst.snapElements[i].left,r=l+inst.snapElements[i].width,t=inst.snapElements[i].top,b=t+inst.snapElements[i].height;if(!((l-d=t&&y1<=b)||(y2>=t&&y2<=b)||(y1b))&&((x1>=l&&x1<=r)||(x2>=l&&x2<=r)||(x1r));break;default:return false;break;}};$.ui.ddmanager={current:null,droppables:{'default':[]},prepareOffsets:function(t,event){var m=$.ui.ddmanager.droppables[t.options.scope];var type=event?event.type:null;var list=(t.currentItem||t.element).find(":data(droppable)").andSelf();droppablesLoop:for(var i=0;i').css({position:this.element.css('position'),width:this.element.outerWidth(),height:this.element.outerHeight(),top:this.element.css('top'),left:this.element.css('left')}));this.element=this.element.parent().data("resizable",this.element.data('resizable'));this.elementIsWrapper=true;this.element.css({marginLeft:this.originalElement.css("marginLeft"),marginTop:this.originalElement.css("marginTop"),marginRight:this.originalElement.css("marginRight"),marginBottom:this.originalElement.css("marginBottom")});this.originalElement.css({marginLeft:0,marginTop:0,marginRight:0,marginBottom:0});this.originalResizeStyle=this.originalElement.css('resize');this.originalElement.css('resize','none');this._proportionallyResizeElements.push(this.originalElement.css({position:'static',zoom:1,display:'block'}));this.originalElement.css({margin:this.originalElement.css('margin')});this._proportionallyResize();} +this.handles=o.handles||(!$('.ui-resizable-handle',this.element).length?"e,s,se":{n:'.ui-resizable-n',e:'.ui-resizable-e',s:'.ui-resizable-s',w:'.ui-resizable-w',se:'.ui-resizable-se',sw:'.ui-resizable-sw',ne:'.ui-resizable-ne',nw:'.ui-resizable-nw'});if(this.handles.constructor==String){if(this.handles=='all')this.handles='n,e,s,w,se,sw,ne,nw';var n=this.handles.split(",");this.handles={};for(var i=0;i');if(/sw|se|ne|nw/.test(handle))axis.css({zIndex:++o.zIndex});if('se'==handle){axis.addClass('ui-icon ui-icon-gripsmall-diagonal-se');};this.handles[handle]='.ui-resizable-'+handle;this.element.append(axis);}} +this._renderAxis=function(target){target=target||this.element;for(var i in this.handles){if(this.handles[i].constructor==String) +this.handles[i]=$(this.handles[i],this.element).show();if(this.elementIsWrapper&&this.originalElement[0].nodeName.match(/textarea|input|select|button/i)){var axis=$(this.handles[i],this.element),padWrapper=0;padWrapper=/sw|ne|nw|se|n|s/.test(i)?axis.outerHeight():axis.outerWidth();var padPos=['padding',/ne|nw|n/.test(i)?'Top':/se|sw|s/.test(i)?'Bottom':/^e$/.test(i)?'Right':'Left'].join("");target.css(padPos,padWrapper);this._proportionallyResize();} +if(!$(this.handles[i]).length) +continue;}};this._renderAxis(this.element);this._handles=$('.ui-resizable-handle',this.element).disableSelection();this._handles.mouseover(function(){if(!self.resizing){if(this.className) +var axis=this.className.match(/ui-resizable-(se|sw|ne|nw|n|e|s|w)/i);self.axis=axis&&axis[1]?axis[1]:'se';}});if(o.autoHide){this._handles.hide();$(this.element).addClass("ui-resizable-autohide").hover(function(){$(this).removeClass("ui-resizable-autohide");self._handles.show();},function(){if(!self.resizing){$(this).addClass("ui-resizable-autohide");self._handles.hide();}});} +this._mouseInit();},destroy:function(){this._mouseDestroy();var _destroy=function(exp){$(exp).removeClass("ui-resizable ui-resizable-disabled ui-resizable-resizing").removeData("resizable").unbind(".resizable").find('.ui-resizable-handle').remove();};if(this.elementIsWrapper){_destroy(this.element);var wrapper=this.element;wrapper.parent().append(this.originalElement.css({position:wrapper.css('position'),width:wrapper.outerWidth(),height:wrapper.outerHeight(),top:wrapper.css('top'),left:wrapper.css('left')})).end().remove();} +this.originalElement.css('resize',this.originalResizeStyle);_destroy(this.originalElement);},_mouseCapture:function(event){var handle=false;for(var i in this.handles){if($(this.handles[i])[0]==event.target)handle=true;} +return this.options.disabled||!!handle;},_mouseStart:function(event){var o=this.options,iniPos=this.element.position(),el=this.element;this.resizing=true;this.documentScroll={top:$(document).scrollTop(),left:$(document).scrollLeft()};if(el.is('.ui-draggable')||(/absolute/).test(el.css('position'))){el.css({position:'absolute',top:iniPos.top,left:iniPos.left});} +if($.browser.opera&&(/relative/).test(el.css('position'))) +el.css({position:'relative',top:'auto',left:'auto'});this._renderProxy();var curleft=num(this.helper.css('left')),curtop=num(this.helper.css('top'));if(o.containment){curleft+=$(o.containment).scrollLeft()||0;curtop+=$(o.containment).scrollTop()||0;} +this.offset=this.helper.offset();this.position={left:curleft,top:curtop};this.size=this._helper?{width:el.outerWidth(),height:el.outerHeight()}:{width:el.width(),height:el.height()};this.originalSize=this._helper?{width:el.outerWidth(),height:el.outerHeight()}:{width:el.width(),height:el.height()};this.originalPosition={left:curleft,top:curtop};this.sizeDiff={width:el.outerWidth()-el.width(),height:el.outerHeight()-el.height()};this.originalMousePosition={left:event.pageX,top:event.pageY};this.aspectRatio=(typeof o.aspectRatio=='number')?o.aspectRatio:((this.originalSize.width/this.originalSize.height)||1);var cursor=$('.ui-resizable-'+this.axis).css('cursor');$('body').css('cursor',cursor=='auto'?this.axis+'-resize':cursor);el.addClass("ui-resizable-resizing");this._propagate("start",event);return true;},_mouseDrag:function(event){var el=this.helper,o=this.options,props={},self=this,smp=this.originalMousePosition,a=this.axis;var dx=(event.pageX-smp.left)||0,dy=(event.pageY-smp.top)||0;var trigger=this._change[a];if(!trigger)return false;var data=trigger.apply(this,[event,dx,dy]),ie6=$.browser.msie&&$.browser.version<7,csdif=this.sizeDiff;if(this._aspectRatio||event.shiftKey) +data=this._updateRatio(data,event);data=this._respectSize(data,event);this._propagate("resize",event);el.css({top:this.position.top+"px",left:this.position.left+"px",width:this.size.width+"px",height:this.size.height+"px"});if(!this._helper&&this._proportionallyResizeElements.length) +this._proportionallyResize();this._updateCache(data);this._trigger('resize',event,this.ui());return false;},_mouseStop:function(event){this.resizing=false;var o=this.options,self=this;if(this._helper){var pr=this._proportionallyResizeElements,ista=pr.length&&(/textarea/i).test(pr[0].nodeName),soffseth=ista&&$.ui.hasScroll(pr[0],'left')?0:self.sizeDiff.height,soffsetw=ista?0:self.sizeDiff.width;var s={width:(self.size.width-soffsetw),height:(self.size.height-soffseth)},left=(parseInt(self.element.css('left'),10)+(self.position.left-self.originalPosition.left))||null,top=(parseInt(self.element.css('top'),10)+(self.position.top-self.originalPosition.top))||null;if(!o.animate) +this.element.css($.extend(s,{top:top,left:left}));self.helper.height(self.size.height);self.helper.width(self.size.width);if(this._helper&&!o.animate)this._proportionallyResize();} +$('body').css('cursor','auto');this.element.removeClass("ui-resizable-resizing");this._propagate("stop",event);if(this._helper)this.helper.remove();return false;},_updateCache:function(data){var o=this.options;this.offset=this.helper.offset();if(isNumber(data.left))this.position.left=data.left;if(isNumber(data.top))this.position.top=data.top;if(isNumber(data.height))this.size.height=data.height;if(isNumber(data.width))this.size.width=data.width;},_updateRatio:function(data,event){var o=this.options,cpos=this.position,csize=this.size,a=this.axis;if(data.height)data.width=(csize.height*this.aspectRatio);else if(data.width)data.height=(csize.width/this.aspectRatio);if(a=='sw'){data.left=cpos.left+(csize.width-data.width);data.top=null;} +if(a=='nw'){data.top=cpos.top+(csize.height-data.height);data.left=cpos.left+(csize.width-data.width);} +return data;},_respectSize:function(data,event){var el=this.helper,o=this.options,pRatio=this._aspectRatio||event.shiftKey,a=this.axis,ismaxw=isNumber(data.width)&&o.maxWidth&&(o.maxWidthdata.width),isminh=isNumber(data.height)&&o.minHeight&&(o.minHeight>data.height);if(isminw)data.width=o.minWidth;if(isminh)data.height=o.minHeight;if(ismaxw)data.width=o.maxWidth;if(ismaxh)data.height=o.maxHeight;var dw=this.originalPosition.left+this.originalSize.width,dh=this.position.top+this.size.height;var cw=/sw|nw|w/.test(a),ch=/nw|ne|n/.test(a);if(isminw&&cw)data.left=dw-o.minWidth;if(ismaxw&&cw)data.left=dw-o.maxWidth;if(isminh&&ch)data.top=dh-o.minHeight;if(ismaxh&&ch)data.top=dh-o.maxHeight;var isNotwh=!data.width&&!data.height;if(isNotwh&&!data.left&&data.top)data.top=null;else if(isNotwh&&!data.top&&data.left)data.left=null;return data;},_proportionallyResize:function(){var o=this.options;if(!this._proportionallyResizeElements.length)return;var element=this.helper||this.element;for(var i=0;i');var ie6=$.browser.msie&&$.browser.version<7,ie6offset=(ie6?1:0),pxyoffset=(ie6?2:-1);this.helper.addClass(this._helper).css({width:this.element.outerWidth()+pxyoffset,height:this.element.outerHeight()+pxyoffset,position:'absolute',left:this.elementOffset.left-ie6offset+'px',top:this.elementOffset.top-ie6offset+'px',zIndex:++o.zIndex});this.helper.appendTo("body").disableSelection();}else{this.helper=this.element;}},_change:{e:function(event,dx,dy){return{width:this.originalSize.width+dx};},w:function(event,dx,dy){var o=this.options,cs=this.originalSize,sp=this.originalPosition;return{left:sp.left+dx,width:cs.width-dx};},n:function(event,dx,dy){var o=this.options,cs=this.originalSize,sp=this.originalPosition;return{top:sp.top+dy,height:cs.height-dy};},s:function(event,dx,dy){return{height:this.originalSize.height+dy};},se:function(event,dx,dy){return $.extend(this._change.s.apply(this,arguments),this._change.e.apply(this,[event,dx,dy]));},sw:function(event,dx,dy){return $.extend(this._change.s.apply(this,arguments),this._change.w.apply(this,[event,dx,dy]));},ne:function(event,dx,dy){return $.extend(this._change.n.apply(this,arguments),this._change.e.apply(this,[event,dx,dy]));},nw:function(event,dx,dy){return $.extend(this._change.n.apply(this,arguments),this._change.w.apply(this,[event,dx,dy]));}},_propagate:function(n,event){$.ui.plugin.call(this,n,[event,this.ui()]);(n!="resize"&&this._trigger(n,event,this.ui()));},plugins:{},ui:function(){return{originalElement:this.originalElement,element:this.element,helper:this.helper,position:this.position,size:this.size,originalSize:this.originalSize,originalPosition:this.originalPosition};}}));$.extend($.ui.resizable,{version:"1.7.2",eventPrefix:"resize",defaults:{alsoResize:false,animate:false,animateDuration:"slow",animateEasing:"swing",aspectRatio:false,autoHide:false,cancel:":input,option",containment:false,delay:0,distance:1,ghost:false,grid:false,handles:"e,s,se",helper:false,maxHeight:null,maxWidth:null,minHeight:10,minWidth:10,zIndex:1000}});$.ui.plugin.add("resizable","alsoResize",{start:function(event,ui){var self=$(this).data("resizable"),o=self.options;_store=function(exp){$(exp).each(function(){$(this).data("resizable-alsoresize",{width:parseInt($(this).width(),10),height:parseInt($(this).height(),10),left:parseInt($(this).css('left'),10),top:parseInt($(this).css('top'),10)});});};if(typeof(o.alsoResize)=='object'&&!o.alsoResize.parentNode){if(o.alsoResize.length){o.alsoResize=o.alsoResize[0];_store(o.alsoResize);} +else{$.each(o.alsoResize,function(exp,c){_store(exp);});}}else{_store(o.alsoResize);}},resize:function(event,ui){var self=$(this).data("resizable"),o=self.options,os=self.originalSize,op=self.originalPosition;var delta={height:(self.size.height-os.height)||0,width:(self.size.width-os.width)||0,top:(self.position.top-op.top)||0,left:(self.position.left-op.left)||0},_alsoResize=function(exp,c){$(exp).each(function(){var el=$(this),start=$(this).data("resizable-alsoresize"),style={},css=c&&c.length?c:['width','height','top','left'];$.each(css||['width','height','top','left'],function(i,prop){var sum=(start[prop]||0)+(delta[prop]||0);if(sum&&sum>=0) +style[prop]=sum||null;});if(/relative/.test(el.css('position'))&&$.browser.opera){self._revertToRelativePosition=true;el.css({position:'absolute',top:'auto',left:'auto'});} +el.css(style);});};if(typeof(o.alsoResize)=='object'&&!o.alsoResize.nodeType){$.each(o.alsoResize,function(exp,c){_alsoResize(exp,c);});}else{_alsoResize(o.alsoResize);}},stop:function(event,ui){var self=$(this).data("resizable");if(self._revertToRelativePosition&&$.browser.opera){self._revertToRelativePosition=false;el.css({position:'relative'});} +$(this).removeData("resizable-alsoresize-start");}});$.ui.plugin.add("resizable","animate",{stop:function(event,ui){var self=$(this).data("resizable"),o=self.options;var pr=self._proportionallyResizeElements,ista=pr.length&&(/textarea/i).test(pr[0].nodeName),soffseth=ista&&$.ui.hasScroll(pr[0],'left')?0:self.sizeDiff.height,soffsetw=ista?0:self.sizeDiff.width;var style={width:(self.size.width-soffsetw),height:(self.size.height-soffseth)},left=(parseInt(self.element.css('left'),10)+(self.position.left-self.originalPosition.left))||null,top=(parseInt(self.element.css('top'),10)+(self.position.top-self.originalPosition.top))||null;self.element.animate($.extend(style,top&&left?{top:top,left:left}:{}),{duration:o.animateDuration,easing:o.animateEasing,step:function(){var data={width:parseInt(self.element.css('width'),10),height:parseInt(self.element.css('height'),10),top:parseInt(self.element.css('top'),10),left:parseInt(self.element.css('left'),10)};if(pr&&pr.length)$(pr[0]).css({width:data.width,height:data.height});self._updateCache(data);self._propagate("resize",event);}});}});$.ui.plugin.add("resizable","containment",{start:function(event,ui){var self=$(this).data("resizable"),o=self.options,el=self.element;var oc=o.containment,ce=(oc instanceof $)?oc.get(0):(/parent/.test(oc))?el.parent().get(0):oc;if(!ce)return;self.containerElement=$(ce);if(/document/.test(oc)||oc==document){self.containerOffset={left:0,top:0};self.containerPosition={left:0,top:0};self.parentData={element:$(document),left:0,top:0,width:$(document).width(),height:$(document).height()||document.body.parentNode.scrollHeight};} +else{var element=$(ce),p=[];$(["Top","Right","Left","Bottom"]).each(function(i,name){p[i]=num(element.css("padding"+name));});self.containerOffset=element.offset();self.containerPosition=element.position();self.containerSize={height:(element.innerHeight()-p[3]),width:(element.innerWidth()-p[1])};var co=self.containerOffset,ch=self.containerSize.height,cw=self.containerSize.width,width=($.ui.hasScroll(ce,"left")?ce.scrollWidth:cw),height=($.ui.hasScroll(ce)?ce.scrollHeight:ch);self.parentData={element:ce,left:co.left,top:co.top,width:width,height:height};}},resize:function(event,ui){var self=$(this).data("resizable"),o=self.options,ps=self.containerSize,co=self.containerOffset,cs=self.size,cp=self.position,pRatio=self._aspectRatio||event.shiftKey,cop={top:0,left:0},ce=self.containerElement;if(ce[0]!=document&&(/static/).test(ce.css('position')))cop=co;if(cp.left<(self._helper?co.left:0)){self.size.width=self.size.width+(self._helper?(self.position.left-co.left):(self.position.left-cop.left));if(pRatio)self.size.height=self.size.width/o.aspectRatio;self.position.left=o.helper?co.left:0;} +if(cp.top<(self._helper?co.top:0)){self.size.height=self.size.height+(self._helper?(self.position.top-co.top):self.position.top);if(pRatio)self.size.width=self.size.height*o.aspectRatio;self.position.top=self._helper?co.top:0;} +self.offset.left=self.parentData.left+self.position.left;self.offset.top=self.parentData.top+self.position.top;var woset=Math.abs((self._helper?self.offset.left-cop.left:(self.offset.left-cop.left))+self.sizeDiff.width),hoset=Math.abs((self._helper?self.offset.top-cop.top:(self.offset.top-co.top))+self.sizeDiff.height);var isParent=self.containerElement.get(0)==self.element.parent().get(0),isOffsetRelative=/relative|absolute/.test(self.containerElement.css('position'));if(isParent&&isOffsetRelative)woset-=self.parentData.left;if(woset+self.size.width>=self.parentData.width){self.size.width=self.parentData.width-woset;if(pRatio)self.size.height=self.size.width/self.aspectRatio;} +if(hoset+self.size.height>=self.parentData.height){self.size.height=self.parentData.height-hoset;if(pRatio)self.size.width=self.size.height*self.aspectRatio;}},stop:function(event,ui){var self=$(this).data("resizable"),o=self.options,cp=self.position,co=self.containerOffset,cop=self.containerPosition,ce=self.containerElement;var helper=$(self.helper),ho=helper.offset(),w=helper.outerWidth()-self.sizeDiff.width,h=helper.outerHeight()-self.sizeDiff.height;if(self._helper&&!o.animate&&(/relative/).test(ce.css('position'))) +$(this).css({left:ho.left-cop.left-co.left,width:w,height:h});if(self._helper&&!o.animate&&(/static/).test(ce.css('position'))) +$(this).css({left:ho.left-cop.left-co.left,width:w,height:h});}});$.ui.plugin.add("resizable","ghost",{start:function(event,ui){var self=$(this).data("resizable"),o=self.options,cs=self.size;self.ghost=self.originalElement.clone();self.ghost.css({opacity:.25,display:'block',position:'relative',height:cs.height,width:cs.width,margin:0,left:0,top:0}).addClass('ui-resizable-ghost').addClass(typeof o.ghost=='string'?o.ghost:'');self.ghost.appendTo(self.helper);},resize:function(event,ui){var self=$(this).data("resizable"),o=self.options;if(self.ghost)self.ghost.css({position:'relative',height:self.size.height,width:self.size.width});},stop:function(event,ui){var self=$(this).data("resizable"),o=self.options;if(self.ghost&&self.helper)self.helper.get(0).removeChild(self.ghost.get(0));}});$.ui.plugin.add("resizable","grid",{resize:function(event,ui){var self=$(this).data("resizable"),o=self.options,cs=self.size,os=self.originalSize,op=self.originalPosition,a=self.axis,ratio=o._aspectRatio||event.shiftKey;o.grid=typeof o.grid=="number"?[o.grid,o.grid]:o.grid;var ox=Math.round((cs.width-os.width)/(o.grid[0]||1))*(o.grid[0]||1),oy=Math.round((cs.height-os.height)/(o.grid[1]||1))*(o.grid[1]||1);if(/^(se|s|e)$/.test(a)){self.size.width=os.width+ox;self.size.height=os.height+oy;} +else if(/^(ne)$/.test(a)){self.size.width=os.width+ox;self.size.height=os.height+oy;self.position.top=op.top-oy;} +else if(/^(sw)$/.test(a)){self.size.width=os.width+ox;self.size.height=os.height+oy;self.position.left=op.left-ox;} +else{self.size.width=os.width+ox;self.size.height=os.height+oy;self.position.top=op.top-oy;self.position.left=op.left-ox;}}});var num=function(v){return parseInt(v,10)||0;};var isNumber=function(value){return!isNaN(parseInt(value,10));};})(jQuery);(function($){$.widget("ui.selectable",$.extend({},$.ui.mouse,{_init:function(){var self=this;this.element.addClass("ui-selectable");this.dragged=false;var selectees;this.refresh=function(){selectees=$(self.options.filter,self.element[0]);selectees.each(function(){var $this=$(this);var pos=$this.offset();$.data(this,"selectable-item",{element:this,$element:$this,left:pos.left,top:pos.top,right:pos.left+$this.outerWidth(),bottom:pos.top+$this.outerHeight(),startselected:false,selected:$this.hasClass('ui-selected'),selecting:$this.hasClass('ui-selecting'),unselecting:$this.hasClass('ui-unselecting')});});};this.refresh();this.selectees=selectees.addClass("ui-selectee");this._mouseInit();this.helper=$(document.createElement('div')).css({border:'1px dotted black'}).addClass("ui-selectable-helper");},destroy:function(){this.element.removeClass("ui-selectable ui-selectable-disabled").removeData("selectable").unbind(".selectable");this._mouseDestroy();},_mouseStart:function(event){var self=this;this.opos=[event.pageX,event.pageY];if(this.options.disabled) +return;var options=this.options;this.selectees=$(options.filter,this.element[0]);this._trigger("start",event);$(options.appendTo).append(this.helper);this.helper.css({"z-index":100,"position":"absolute","left":event.clientX,"top":event.clientY,"width":0,"height":0});if(options.autoRefresh){this.refresh();} +this.selectees.filter('.ui-selected').each(function(){var selectee=$.data(this,"selectable-item");selectee.startselected=true;if(!event.metaKey){selectee.$element.removeClass('ui-selected');selectee.selected=false;selectee.$element.addClass('ui-unselecting');selectee.unselecting=true;self._trigger("unselecting",event,{unselecting:selectee.element});}});$(event.target).parents().andSelf().each(function(){var selectee=$.data(this,"selectable-item");if(selectee){selectee.$element.removeClass("ui-unselecting").addClass('ui-selecting');selectee.unselecting=false;selectee.selecting=true;selectee.selected=true;self._trigger("selecting",event,{selecting:selectee.element});return false;}});},_mouseDrag:function(event){var self=this;this.dragged=true;if(this.options.disabled) +return;var options=this.options;var x1=this.opos[0],y1=this.opos[1],x2=event.pageX,y2=event.pageY;if(x1>x2){var tmp=x2;x2=x1;x1=tmp;} +if(y1>y2){var tmp=y2;y2=y1;y1=tmp;} +this.helper.css({left:x1,top:y1,width:x2-x1,height:y2-y1});this.selectees.each(function(){var selectee=$.data(this,"selectable-item");if(!selectee||selectee.element==self.element[0]) +return;var hit=false;if(options.tolerance=='touch'){hit=(!(selectee.left>x2||selectee.righty2||selectee.bottomx1&&selectee.righty1&&selectee.bottom=0;i--) +this.items[i].item.removeData("sortable-item");},_mouseCapture:function(event,overrideHandle){if(this.reverting){return false;} +if(this.options.disabled||this.options.type=='static')return false;this._refreshItems(event);var currentItem=null,self=this,nodes=$(event.target).parents().each(function(){if($.data(this,'sortable-item')==self){currentItem=$(this);return false;}});if($.data(event.target,'sortable-item')==self)currentItem=$(event.target);if(!currentItem)return false;if(this.options.handle&&!overrideHandle){var validHandle=false;$(this.options.handle,currentItem).find("*").andSelf().each(function(){if(this==event.target)validHandle=true;});if(!validHandle)return false;} +this.currentItem=currentItem;this._removeCurrentsFromItems();return true;},_mouseStart:function(event,overrideHandle,noActivation){var o=this.options,self=this;this.currentContainer=this;this.refreshPositions();this.helper=this._createHelper(event);this._cacheHelperProportions();this._cacheMargins();this.scrollParent=this.helper.scrollParent();this.offset=this.currentItem.offset();this.offset={top:this.offset.top-this.margins.top,left:this.offset.left-this.margins.left};this.helper.css("position","absolute");this.cssPosition=this.helper.css("position");$.extend(this.offset,{click:{left:event.pageX-this.offset.left,top:event.pageY-this.offset.top},parent:this._getParentOffset(),relative:this._getRelativeOffset()});this.originalPosition=this._generatePosition(event);this.originalPageX=event.pageX;this.originalPageY=event.pageY;if(o.cursorAt) +this._adjustOffsetFromHelper(o.cursorAt);this.domPosition={prev:this.currentItem.prev()[0],parent:this.currentItem.parent()[0]};if(this.helper[0]!=this.currentItem[0]){this.currentItem.hide();} +this._createPlaceholder();if(o.containment) +this._setContainment();if(o.cursor){if($('body').css("cursor"))this._storedCursor=$('body').css("cursor");$('body').css("cursor",o.cursor);} +if(o.opacity){if(this.helper.css("opacity"))this._storedOpacity=this.helper.css("opacity");this.helper.css("opacity",o.opacity);} +if(o.zIndex){if(this.helper.css("zIndex"))this._storedZIndex=this.helper.css("zIndex");this.helper.css("zIndex",o.zIndex);} +if(this.scrollParent[0]!=document&&this.scrollParent[0].tagName!='HTML') +this.overflowOffset=this.scrollParent.offset();this._trigger("start",event,this._uiHash());if(!this._preserveHelperProportions) +this._cacheHelperProportions();if(!noActivation){for(var i=this.containers.length-1;i>=0;i--){this.containers[i]._trigger("activate",event,self._uiHash(this));}} +if($.ui.ddmanager) +$.ui.ddmanager.current=this;if($.ui.ddmanager&&!o.dropBehaviour) +$.ui.ddmanager.prepareOffsets(this,event);this.dragging=true;this.helper.addClass("ui-sortable-helper");this._mouseDrag(event);return true;},_mouseDrag:function(event){this.position=this._generatePosition(event);this.positionAbs=this._convertPositionTo("absolute");if(!this.lastPositionAbs){this.lastPositionAbs=this.positionAbs;} +if(this.options.scroll){var o=this.options,scrolled=false;if(this.scrollParent[0]!=document&&this.scrollParent[0].tagName!='HTML'){if((this.overflowOffset.top+this.scrollParent[0].offsetHeight)-event.pageY=0;i--){var item=this.items[i],itemElement=item.item[0],intersection=this._intersectsWithPointer(item);if(!intersection)continue;if(itemElement!=this.currentItem[0]&&this.placeholder[intersection==1?"next":"prev"]()[0]!=itemElement&&!$.ui.contains(this.placeholder[0],itemElement)&&(this.options.type=='semi-dynamic'?!$.ui.contains(this.element[0],itemElement):true)){this.direction=intersection==1?"down":"up";if(this.options.tolerance=="pointer"||this._intersectsWithSides(item)){this._rearrange(event,item);}else{break;} +this._trigger("change",event,this._uiHash());break;}} +this._contactContainers(event);if($.ui.ddmanager)$.ui.ddmanager.drag(this,event);this._trigger('sort',event,this._uiHash());this.lastPositionAbs=this.positionAbs;return false;},_mouseStop:function(event,noPropagation){if(!event)return;if($.ui.ddmanager&&!this.options.dropBehaviour) +$.ui.ddmanager.drop(this,event);if(this.options.revert){var self=this;var cur=self.placeholder.offset();self.reverting=true;$(this.helper).animate({left:cur.left-this.offset.parent.left-self.margins.left+(this.offsetParent[0]==document.body?0:this.offsetParent[0].scrollLeft),top:cur.top-this.offset.parent.top-self.margins.top+(this.offsetParent[0]==document.body?0:this.offsetParent[0].scrollTop)},parseInt(this.options.revert,10)||500,function(){self._clear(event);});}else{this._clear(event,noPropagation);} +return false;},cancel:function(){var self=this;if(this.dragging){this._mouseUp();if(this.options.helper=="original") +this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper");else +this.currentItem.show();for(var i=this.containers.length-1;i>=0;i--){this.containers[i]._trigger("deactivate",null,self._uiHash(this));if(this.containers[i].containerCache.over){this.containers[i]._trigger("out",null,self._uiHash(this));this.containers[i].containerCache.over=0;}}} +if(this.placeholder[0].parentNode)this.placeholder[0].parentNode.removeChild(this.placeholder[0]);if(this.options.helper!="original"&&this.helper&&this.helper[0].parentNode)this.helper.remove();$.extend(this,{helper:null,dragging:false,reverting:false,_noFinalSort:null});if(this.domPosition.prev){$(this.domPosition.prev).after(this.currentItem);}else{$(this.domPosition.parent).prepend(this.currentItem);} +return true;},serialize:function(o){var items=this._getItemsAsjQuery(o&&o.connected);var str=[];o=o||{};$(items).each(function(){var res=($(o.item||this).attr(o.attribute||'id')||'').match(o.expression||(/(.+)[-=_](.+)/));if(res)str.push((o.key||res[1]+'[]')+'='+(o.key&&o.expression?res[1]:res[2]));});return str.join('&');},toArray:function(o){var items=this._getItemsAsjQuery(o&&o.connected);var ret=[];o=o||{};items.each(function(){ret.push($(o.item||this).attr(o.attribute||'id')||'');});return ret;},_intersectsWith:function(item){var x1=this.positionAbs.left,x2=x1+this.helperProportions.width,y1=this.positionAbs.top,y2=y1+this.helperProportions.height;var l=item.left,r=l+item.width,t=item.top,b=t+item.height;var dyClick=this.offset.click.top,dxClick=this.offset.click.left;var isOverElement=(y1+dyClick)>t&&(y1+dyClick)l&&(x1+dxClick)item[this.floating?'width':'height'])){return isOverElement;}else{return(l0?"down":"up");},_getDragHorizontalDirection:function(){var delta=this.positionAbs.left-this.lastPositionAbs.left;return delta!=0&&(delta>0?"right":"left");},refresh:function(event){this._refreshItems(event);this.refreshPositions();},_connectWith:function(){var options=this.options;return options.connectWith.constructor==String?[options.connectWith]:options.connectWith;},_getItemsAsjQuery:function(connected){var self=this;var items=[];var queries=[];var connectWith=this._connectWith();if(connectWith&&connected){for(var i=connectWith.length-1;i>=0;i--){var cur=$(connectWith[i]);for(var j=cur.length-1;j>=0;j--){var inst=$.data(cur[j],'sortable');if(inst&&inst!=this&&!inst.options.disabled){queries.push([$.isFunction(inst.options.items)?inst.options.items.call(inst.element):$(inst.options.items,inst.element).not(".ui-sortable-helper"),inst]);}};};} +queries.push([$.isFunction(this.options.items)?this.options.items.call(this.element,null,{options:this.options,item:this.currentItem}):$(this.options.items,this.element).not(".ui-sortable-helper"),this]);for(var i=queries.length-1;i>=0;i--){queries[i][0].each(function(){items.push(this);});};return $(items);},_removeCurrentsFromItems:function(){var list=this.currentItem.find(":data(sortable-item)");for(var i=0;i=0;i--){var cur=$(connectWith[i]);for(var j=cur.length-1;j>=0;j--){var inst=$.data(cur[j],'sortable');if(inst&&inst!=this&&!inst.options.disabled){queries.push([$.isFunction(inst.options.items)?inst.options.items.call(inst.element[0],event,{item:this.currentItem}):$(inst.options.items,inst.element),inst]);this.containers.push(inst);}};};} +for(var i=queries.length-1;i>=0;i--){var targetData=queries[i][1];var _queries=queries[i][0];for(var j=0,queriesLength=_queries.length;j=0;i--){var item=this.items[i];if(item.instance!=this.currentContainer&&this.currentContainer&&item.item[0]!=this.currentItem[0]) +continue;var t=this.options.toleranceElement?$(this.options.toleranceElement,item.item):item.item;if(!fast){item.width=t.outerWidth();item.height=t.outerHeight();} +var p=t.offset();item.left=p.left;item.top=p.top;};if(this.options.custom&&this.options.custom.refreshContainers){this.options.custom.refreshContainers.call(this);}else{for(var i=this.containers.length-1;i>=0;i--){var p=this.containers[i].element.offset();this.containers[i].containerCache.left=p.left;this.containers[i].containerCache.top=p.top;this.containers[i].containerCache.width=this.containers[i].element.outerWidth();this.containers[i].containerCache.height=this.containers[i].element.outerHeight();};}},_createPlaceholder:function(that){var self=that||this,o=self.options;if(!o.placeholder||o.placeholder.constructor==String){var className=o.placeholder;o.placeholder={element:function(){var el=$(document.createElement(self.currentItem[0].nodeName)).addClass(className||self.currentItem[0].className+" ui-sortable-placeholder").removeClass("ui-sortable-helper")[0];if(!className) +el.style.visibility="hidden";return el;},update:function(container,p){if(className&&!o.forcePlaceholderSize)return;if(!p.height()){p.height(self.currentItem.innerHeight()-parseInt(self.currentItem.css('paddingTop')||0,10)-parseInt(self.currentItem.css('paddingBottom')||0,10));};if(!p.width()){p.width(self.currentItem.innerWidth()-parseInt(self.currentItem.css('paddingLeft')||0,10)-parseInt(self.currentItem.css('paddingRight')||0,10));};}};} +self.placeholder=$(o.placeholder.element.call(self.element,self.currentItem));self.currentItem.after(self.placeholder);o.placeholder.update(self,self.placeholder);},_contactContainers:function(event){for(var i=this.containers.length-1;i>=0;i--){if(this._intersectsWith(this.containers[i].containerCache)){if(!this.containers[i].containerCache.over){if(this.currentContainer!=this.containers[i]){var dist=10000;var itemWithLeastDistance=null;var base=this.positionAbs[this.containers[i].floating?'left':'top'];for(var j=this.items.length-1;j>=0;j--){if(!$.ui.contains(this.containers[i].element[0],this.items[j].item[0]))continue;var cur=this.items[j][this.containers[i].floating?'left':'top'];if(Math.abs(cur-base)this.containment[2])pageX=this.containment[2]+this.offset.click.left;if(event.pageY-this.offset.click.top>this.containment[3])pageY=this.containment[3]+this.offset.click.top;} +if(o.grid){var top=this.originalPageY+Math.round((pageY-this.originalPageY)/o.grid[1])*o.grid[1];pageY=this.containment?(!(top-this.offset.click.topthis.containment[3])?top:(!(top-this.offset.click.topthis.containment[2])?left:(!(left-this.offset.click.left=0;i--){if($.ui.contains(this.containers[i].element[0],this.currentItem[0])&&!noPropagation){delayedTriggers.push((function(c){return function(event){c._trigger("receive",event,this._uiHash(this));};}).call(this,this.containers[i]));delayedTriggers.push((function(c){return function(event){c._trigger("update",event,this._uiHash(this));};}).call(this,this.containers[i]));}};};for(var i=this.containers.length-1;i>=0;i--){if(!noPropagation)delayedTriggers.push((function(c){return function(event){c._trigger("deactivate",event,this._uiHash(this));};}).call(this,this.containers[i]));if(this.containers[i].containerCache.over){delayedTriggers.push((function(c){return function(event){c._trigger("out",event,this._uiHash(this));};}).call(this,this.containers[i]));this.containers[i].containerCache.over=0;}} +if(this._storedCursor)$('body').css("cursor",this._storedCursor);if(this._storedOpacity)this.helper.css("opacity",this._storedOpacity);if(this._storedZIndex)this.helper.css("zIndex",this._storedZIndex=='auto'?'':this._storedZIndex);this.dragging=false;if(this.cancelHelperRemoval){if(!noPropagation){this._trigger("beforeStop",event,this._uiHash());for(var i=0;i *',opacity:false,placeholder:false,revert:false,scroll:true,scrollSensitivity:20,scrollSpeed:20,scope:"default",tolerance:"intersect",zIndex:1000}});})(jQuery);(function($){$.widget("ui.accordion",{_init:function(){var o=this.options,self=this;this.running=0;if(o.collapsible==$.ui.accordion.defaults.collapsible&&o.alwaysOpen!=$.ui.accordion.defaults.alwaysOpen){o.collapsible=!o.alwaysOpen;} +if(o.navigation){var current=this.element.find("a").filter(o.navigationFilter);if(current.length){if(current.filter(o.header).length){this.active=current;}else{this.active=current.parent().parent().prev();current.addClass("ui-accordion-content-active");}}} +this.element.addClass("ui-accordion ui-widget ui-helper-reset");if(this.element[0].nodeName=="UL"){this.element.children("li").addClass("ui-accordion-li-fix");} +this.headers=this.element.find(o.header).addClass("ui-accordion-header ui-helper-reset ui-state-default ui-corner-all").bind("mouseenter.accordion",function(){$(this).addClass('ui-state-hover');}).bind("mouseleave.accordion",function(){$(this).removeClass('ui-state-hover');}).bind("focus.accordion",function(){$(this).addClass('ui-state-focus');}).bind("blur.accordion",function(){$(this).removeClass('ui-state-focus');});this.headers.next().addClass("ui-accordion-content ui-helper-reset ui-widget-content ui-corner-bottom");this.active=this._findActive(this.active||o.active).toggleClass("ui-state-default").toggleClass("ui-state-active").toggleClass("ui-corner-all").toggleClass("ui-corner-top");this.active.next().addClass('ui-accordion-content-active');$("").addClass("ui-icon "+o.icons.header).prependTo(this.headers);this.active.find(".ui-icon").toggleClass(o.icons.header).toggleClass(o.icons.headerSelected);if($.browser.msie){this.element.find('a').css('zoom','1');} +this.resize();this.element.attr('role','tablist');this.headers.attr('role','tab').bind('keydown',function(event){return self._keydown(event);}).next().attr('role','tabpanel');this.headers.not(this.active||"").attr('aria-expanded','false').attr("tabIndex","-1").next().hide();if(!this.active.length){this.headers.eq(0).attr('tabIndex','0');}else{this.active.attr('aria-expanded','true').attr('tabIndex','0');} +if(!$.browser.safari) +this.headers.find('a').attr('tabIndex','-1');if(o.event){this.headers.bind((o.event)+".accordion",function(event){return self._clickHandler.call(self,event,this);});}},destroy:function(){var o=this.options;this.element.removeClass("ui-accordion ui-widget ui-helper-reset").removeAttr("role").unbind('.accordion').removeData('accordion');this.headers.unbind(".accordion").removeClass("ui-accordion-header ui-helper-reset ui-state-default ui-corner-all ui-state-active ui-corner-top").removeAttr("role").removeAttr("aria-expanded").removeAttr("tabindex");this.headers.find("a").removeAttr("tabindex");this.headers.children(".ui-icon").remove();var contents=this.headers.next().css("display","").removeAttr("role").removeClass("ui-helper-reset ui-widget-content ui-corner-bottom ui-accordion-content ui-accordion-content-active");if(o.autoHeight||o.fillHeight){contents.css("height","");}},_setData:function(key,value){if(key=='alwaysOpen'){key='collapsible';value=!value;} +$.widget.prototype._setData.apply(this,arguments);},_keydown:function(event){var o=this.options,keyCode=$.ui.keyCode;if(o.disabled||event.altKey||event.ctrlKey) +return;var length=this.headers.length;var currentIndex=this.headers.index(event.target);var toFocus=false;switch(event.keyCode){case keyCode.RIGHT:case keyCode.DOWN:toFocus=this.headers[(currentIndex+1)%length];break;case keyCode.LEFT:case keyCode.UP:toFocus=this.headers[(currentIndex-1+length)%length];break;case keyCode.SPACE:case keyCode.ENTER:return this._clickHandler({target:event.target},event.target);} +if(toFocus){$(event.target).attr('tabIndex','-1');$(toFocus).attr('tabIndex','0');toFocus.focus();return false;} +return true;},resize:function(){var o=this.options,maxHeight;if(o.fillSpace){if($.browser.msie){var defOverflow=this.element.parent().css('overflow');this.element.parent().css('overflow','hidden');} +maxHeight=this.element.parent().height();if($.browser.msie){this.element.parent().css('overflow',defOverflow);} +this.headers.each(function(){maxHeight-=$(this).outerHeight();});var maxPadding=0;this.headers.next().each(function(){maxPadding=Math.max(maxPadding,$(this).innerHeight()-$(this).height());}).height(Math.max(0,maxHeight-maxPadding)).css('overflow','auto');}else if(o.autoHeight){maxHeight=0;this.headers.next().each(function(){maxHeight=Math.max(maxHeight,$(this).outerHeight());}).height(maxHeight);}},activate:function(index){var active=this._findActive(index)[0];this._clickHandler({target:active},active);},_findActive:function(selector){return selector?typeof selector=="number"?this.headers.filter(":eq("+selector+")"):this.headers.not(this.headers.not(selector)):selector===false?$([]):this.headers.filter(":eq(0)");},_clickHandler:function(event,target){var o=this.options;if(o.disabled)return false;if(!event.target&&o.collapsible){this.active.removeClass("ui-state-active ui-corner-top").addClass("ui-state-default ui-corner-all").find(".ui-icon").removeClass(o.icons.headerSelected).addClass(o.icons.header);this.active.next().addClass('ui-accordion-content-active');var toHide=this.active.next(),data={options:o,newHeader:$([]),oldHeader:o.active,newContent:$([]),oldContent:toHide},toShow=(this.active=$([]));this._toggle(toShow,toHide,data);return false;} +var clicked=$(event.currentTarget||target);var clickedIsActive=clicked[0]==this.active[0];if(this.running||(!o.collapsible&&clickedIsActive)){return false;} +this.active.removeClass("ui-state-active ui-corner-top").addClass("ui-state-default ui-corner-all").find(".ui-icon").removeClass(o.icons.headerSelected).addClass(o.icons.header);this.active.next().addClass('ui-accordion-content-active');if(!clickedIsActive){clicked.removeClass("ui-state-default ui-corner-all").addClass("ui-state-active ui-corner-top").find(".ui-icon").removeClass(o.icons.header).addClass(o.icons.headerSelected);clicked.next().addClass('ui-accordion-content-active');} +var toShow=clicked.next(),toHide=this.active.next(),data={options:o,newHeader:clickedIsActive&&o.collapsible?$([]):clicked,oldHeader:this.active,newContent:clickedIsActive&&o.collapsible?$([]):toShow.find('> *'),oldContent:toHide.find('> *')},down=this.headers.index(this.active[0])>this.headers.index(clicked[0]);this.active=clickedIsActive?$([]):clicked;this._toggle(toShow,toHide,data,clickedIsActive,down);return false;},_toggle:function(toShow,toHide,data,clickedIsActive,down){var o=this.options,self=this;this.toShow=toShow;this.toHide=toHide;this.data=data;var complete=function(){if(!self)return;return self._completed.apply(self,arguments);};this._trigger("changestart",null,this.data);this.running=toHide.size()===0?toShow.size():toHide.size();if(o.animated){var animOptions={};if(o.collapsible&&clickedIsActive){animOptions={toShow:$([]),toHide:toHide,complete:complete,down:down,autoHeight:o.autoHeight||o.fillSpace};}else{animOptions={toShow:toShow,toHide:toHide,complete:complete,down:down,autoHeight:o.autoHeight||o.fillSpace};} +if(!o.proxied){o.proxied=o.animated;} +if(!o.proxiedDuration){o.proxiedDuration=o.duration;} +o.animated=$.isFunction(o.proxied)?o.proxied(animOptions):o.proxied;o.duration=$.isFunction(o.proxiedDuration)?o.proxiedDuration(animOptions):o.proxiedDuration;var animations=$.ui.accordion.animations,duration=o.duration,easing=o.animated;if(!animations[easing]){animations[easing]=function(options){this.slide(options,{easing:easing,duration:duration||700});};} +animations[easing](animOptions);}else{if(o.collapsible&&clickedIsActive){toShow.toggle();}else{toHide.hide();toShow.show();} +complete(true);} +toHide.prev().attr('aria-expanded','false').attr("tabIndex","-1").blur();toShow.prev().attr('aria-expanded','true').attr("tabIndex","0").focus();},_completed:function(cancel){var o=this.options;this.running=cancel?0:--this.running;if(this.running)return;if(o.clearStyle){this.toShow.add(this.toHide).css({height:"",overflow:""});} +this._trigger('change',null,this.data);}});$.extend($.ui.accordion,{version:"1.7.2",defaults:{active:null,alwaysOpen:true,animated:'slide',autoHeight:true,clearStyle:false,collapsible:false,event:"click",fillSpace:false,header:"> li > :first-child,> :not(li):even",icons:{header:"ui-icon-triangle-1-e",headerSelected:"ui-icon-triangle-1-s"},navigation:false,navigationFilter:function(){return this.href.toLowerCase()==location.href.toLowerCase();}},animations:{slide:function(options,additions){options=$.extend({easing:"swing",duration:300},options,additions);if(!options.toHide.size()){options.toShow.animate({height:"show"},options);return;} +if(!options.toShow.size()){options.toHide.animate({height:"hide"},options);return;} +var overflow=options.toShow.css('overflow'),percentDone,showProps={},hideProps={},fxAttrs=["height","paddingTop","paddingBottom"],originalWidth;var s=options.toShow;originalWidth=s[0].style.width;s.width(parseInt(s.parent().width(),10)-parseInt(s.css("paddingLeft"),10)-parseInt(s.css("paddingRight"),10)-(parseInt(s.css("borderLeftWidth"),10)||0)-(parseInt(s.css("borderRightWidth"),10)||0));$.each(fxAttrs,function(i,prop){hideProps[prop]='hide';var parts=(''+$.css(options.toShow[0],prop)).match(/^([\d+-.]+)(.*)$/);showProps[prop]={value:parts[1],unit:parts[2]||'px'};});options.toShow.css({height:0,overflow:'hidden'}).show();options.toHide.filter(":hidden").each(options.complete).end().filter(":visible").animate(hideProps,{step:function(now,settings){if(settings.prop=='height'){percentDone=(settings.now-settings.start)/(settings.end-settings.start);} +options.toShow[0].style[settings.prop]=(percentDone*showProps[settings.prop].value)+showProps[settings.prop].unit;},duration:options.duration,easing:options.easing,complete:function(){if(!options.autoHeight){options.toShow.css("height","");} +options.toShow.css("width",originalWidth);options.toShow.css({overflow:overflow});options.complete();}});},bounceslide:function(options){this.slide(options,{easing:options.down?"easeOutBounce":"swing",duration:options.down?1000:200});},easeslide:function(options){this.slide(options,{easing:"easeinout",duration:700});}}});})(jQuery);(function($){var setDataSwitch={dragStart:"start.draggable",drag:"drag.draggable",dragStop:"stop.draggable",maxHeight:"maxHeight.resizable",minHeight:"minHeight.resizable",maxWidth:"maxWidth.resizable",minWidth:"minWidth.resizable",resizeStart:"start.resizable",resize:"drag.resizable",resizeStop:"stop.resizable"},uiDialogClasses='ui-dialog '+'ui-widget '+'ui-widget-content '+'ui-corner-all ';$.widget("ui.dialog",{_init:function(){this.originalTitle=this.element.attr('title');var self=this,options=this.options,title=options.title||this.originalTitle||' ',titleId=$.ui.dialog.getTitleId(this.element),uiDialog=(this.uiDialog=$('
                ')).appendTo(document.body).hide().addClass(uiDialogClasses+options.dialogClass).css({position:'absolute',overflow:'hidden',zIndex:options.zIndex}).attr('tabIndex',-1).css('outline',0).keydown(function(event){(options.closeOnEscape&&event.keyCode&&event.keyCode==$.ui.keyCode.ESCAPE&&self.close(event));}).attr({role:'dialog','aria-labelledby':titleId}).mousedown(function(event){self.moveToTop(false,event);}),uiDialogContent=this.element.show().removeAttr('title').addClass('ui-dialog-content '+'ui-widget-content').appendTo(uiDialog),uiDialogTitlebar=(this.uiDialogTitlebar=$('
                ')).addClass('ui-dialog-titlebar '+'ui-widget-header '+'ui-corner-all '+'ui-helper-clearfix').prependTo(uiDialog),uiDialogTitlebarClose=$('').addClass('ui-dialog-titlebar-close '+'ui-corner-all').attr('role','button').hover(function(){uiDialogTitlebarClose.addClass('ui-state-hover');},function(){uiDialogTitlebarClose.removeClass('ui-state-hover');}).focus(function(){uiDialogTitlebarClose.addClass('ui-state-focus');}).blur(function(){uiDialogTitlebarClose.removeClass('ui-state-focus');}).mousedown(function(ev){ev.stopPropagation();}).click(function(event){self.close(event);return false;}).appendTo(uiDialogTitlebar),uiDialogTitlebarCloseText=(this.uiDialogTitlebarCloseText=$('')).addClass('ui-icon '+'ui-icon-closethick').text(options.closeText).appendTo(uiDialogTitlebarClose),uiDialogTitle=$('').addClass('ui-dialog-title').attr('id',titleId).html(title).prependTo(uiDialogTitlebar);uiDialogTitlebar.find("*").add(uiDialogTitlebar).disableSelection();(options.draggable&&$.fn.draggable&&this._makeDraggable());(options.resizable&&$.fn.resizable&&this._makeResizable());this._createButtons(options.buttons);this._isOpen=false;(options.bgiframe&&$.fn.bgiframe&&uiDialog.bgiframe());(options.autoOpen&&this.open());},destroy:function(){(this.overlay&&this.overlay.destroy());this.uiDialog.hide();this.element.unbind('.dialog').removeData('dialog').removeClass('ui-dialog-content ui-widget-content').hide().appendTo('body');this.uiDialog.remove();(this.originalTitle&&this.element.attr('title',this.originalTitle));},close:function(event){var self=this;if(false===self._trigger('beforeclose',event)){return;} +(self.overlay&&self.overlay.destroy());self.uiDialog.unbind('keypress.ui-dialog');(self.options.hide?self.uiDialog.hide(self.options.hide,function(){self._trigger('close',event);}):self.uiDialog.hide()&&self._trigger('close',event));$.ui.dialog.overlay.resize();self._isOpen=false;if(self.options.modal){var maxZ=0;$('.ui-dialog').each(function(){if(this!=self.uiDialog[0]){maxZ=Math.max(maxZ,$(this).css('z-index'));}});$.ui.dialog.maxZ=maxZ;}},isOpen:function(){return this._isOpen;},moveToTop:function(force,event){if((this.options.modal&&!force)||(!this.options.stack&&!this.options.modal)){return this._trigger('focus',event);} +if(this.options.zIndex>$.ui.dialog.maxZ){$.ui.dialog.maxZ=this.options.zIndex;} +(this.overlay&&this.overlay.$el.css('z-index',$.ui.dialog.overlay.maxZ=++$.ui.dialog.maxZ));var saveScroll={scrollTop:this.element.attr('scrollTop'),scrollLeft:this.element.attr('scrollLeft')};this.uiDialog.css('z-index',++$.ui.dialog.maxZ);this.element.attr(saveScroll);this._trigger('focus',event);},open:function(){if(this._isOpen){return;} +var options=this.options,uiDialog=this.uiDialog;this.overlay=options.modal?new $.ui.dialog.overlay(this):null;(uiDialog.next().length&&uiDialog.appendTo('body'));this._size();this._position(options.position);uiDialog.show(options.show);this.moveToTop(true);(options.modal&&uiDialog.bind('keypress.ui-dialog',function(event){if(event.keyCode!=$.ui.keyCode.TAB){return;} +var tabbables=$(':tabbable',this),first=tabbables.filter(':first')[0],last=tabbables.filter(':last')[0];if(event.target==last&&!event.shiftKey){setTimeout(function(){first.focus();},1);}else if(event.target==first&&event.shiftKey){setTimeout(function(){last.focus();},1);}}));$([]).add(uiDialog.find('.ui-dialog-content :tabbable:first')).add(uiDialog.find('.ui-dialog-buttonpane :tabbable:first')).add(uiDialog).filter(':first').focus();this._trigger('open');this._isOpen=true;},_createButtons:function(buttons){var self=this,hasButtons=false,uiDialogButtonPane=$('
                ').addClass('ui-dialog-buttonpane '+'ui-widget-content '+'ui-helper-clearfix');this.uiDialog.find('.ui-dialog-buttonpane').remove();(typeof buttons=='object'&&buttons!==null&&$.each(buttons,function(){return!(hasButtons=true);}));if(hasButtons){$.each(buttons,function(name,fn){$('').addClass('ui-state-default '+'ui-corner-all').text(name).click(function(){fn.apply(self.element[0],arguments);}).hover(function(){$(this).addClass('ui-state-hover');},function(){$(this).removeClass('ui-state-hover');}).focus(function(){$(this).addClass('ui-state-focus');}).blur(function(){$(this).removeClass('ui-state-focus');}).appendTo(uiDialogButtonPane);});uiDialogButtonPane.appendTo(this.uiDialog);}},_makeDraggable:function(){var self=this,options=this.options,heightBeforeDrag;this.uiDialog.draggable({cancel:'.ui-dialog-content',handle:'.ui-dialog-titlebar',containment:'document',start:function(){heightBeforeDrag=options.height;$(this).height($(this).height()).addClass("ui-dialog-dragging");(options.dragStart&&options.dragStart.apply(self.element[0],arguments));},drag:function(){(options.drag&&options.drag.apply(self.element[0],arguments));},stop:function(){$(this).removeClass("ui-dialog-dragging").height(heightBeforeDrag);(options.dragStop&&options.dragStop.apply(self.element[0],arguments));$.ui.dialog.overlay.resize();}});},_makeResizable:function(handles){handles=(handles===undefined?this.options.resizable:handles);var self=this,options=this.options,resizeHandles=typeof handles=='string'?handles:'n,e,s,w,se,sw,ne,nw';this.uiDialog.resizable({cancel:'.ui-dialog-content',alsoResize:this.element,maxWidth:options.maxWidth,maxHeight:options.maxHeight,minWidth:options.minWidth,minHeight:options.minHeight,start:function(){$(this).addClass("ui-dialog-resizing");(options.resizeStart&&options.resizeStart.apply(self.element[0],arguments));},resize:function(){(options.resize&&options.resize.apply(self.element[0],arguments));},handles:resizeHandles,stop:function(){$(this).removeClass("ui-dialog-resizing");options.height=$(this).height();options.width=$(this).width();(options.resizeStop&&options.resizeStop.apply(self.element[0],arguments));$.ui.dialog.overlay.resize();}}).find('.ui-resizable-se').addClass('ui-icon ui-icon-grip-diagonal-se');},_position:function(pos){var wnd=$(window),doc=$(document),pTop=doc.scrollTop(),pLeft=doc.scrollLeft(),minTop=pTop;if($.inArray(pos,['center','top','right','bottom','left'])>=0){pos=[pos=='right'||pos=='left'?pos:'center',pos=='top'||pos=='bottom'?pos:'middle'];} +if(pos.constructor!=Array){pos=['center','middle'];} +if(pos[0].constructor==Number){pLeft+=pos[0];}else{switch(pos[0]){case'left':pLeft+=0;break;case'right':pLeft+=wnd.width()-this.uiDialog.outerWidth();break;default:case'center':pLeft+=(wnd.width()-this.uiDialog.outerWidth())/2;}} +if(pos[1].constructor==Number){pTop+=pos[1];}else{switch(pos[1]){case'top':pTop+=0;break;case'bottom':pTop+=wnd.height()-this.uiDialog.outerHeight();break;default:case'middle':pTop+=(wnd.height()-this.uiDialog.outerHeight())/2;}} +pTop=Math.max(pTop,minTop);this.uiDialog.css({top:pTop,left:pLeft});},_setData:function(key,value){(setDataSwitch[key]&&this.uiDialog.data(setDataSwitch[key],value));switch(key){case"buttons":this._createButtons(value);break;case"closeText":this.uiDialogTitlebarCloseText.text(value);break;case"dialogClass":this.uiDialog.removeClass(this.options.dialogClass).addClass(uiDialogClasses+value);break;case"draggable":(value?this._makeDraggable():this.uiDialog.draggable('destroy'));break;case"height":this.uiDialog.height(value);break;case"position":this._position(value);break;case"resizable":var uiDialog=this.uiDialog,isResizable=this.uiDialog.is(':data(resizable)');(isResizable&&!value&&uiDialog.resizable('destroy'));(isResizable&&typeof value=='string'&&uiDialog.resizable('option','handles',value));(isResizable||this._makeResizable(value));break;case"title":$(".ui-dialog-title",this.uiDialogTitlebar).html(value||' ');break;case"width":this.uiDialog.width(value);break;} +$.widget.prototype._setData.apply(this,arguments);},_size:function(){var options=this.options;this.element.css({height:0,minHeight:0,width:'auto'});var nonContentHeight=this.uiDialog.css({height:'auto',width:options.width}).height();this.element.css({minHeight:Math.max(options.minHeight-nonContentHeight,0),height:options.height=='auto'?'auto':Math.max(options.height-nonContentHeight,0)});}});$.extend($.ui.dialog,{version:"1.7.2",defaults:{autoOpen:true,bgiframe:false,buttons:{},closeOnEscape:true,closeText:'close',dialogClass:'',draggable:true,hide:null,height:'auto',maxHeight:false,maxWidth:false,minHeight:150,minWidth:150,modal:false,position:'center',resizable:true,show:null,stack:true,title:'',width:300,zIndex:1000},getter:'isOpen',uuid:0,maxZ:0,getTitleId:function($el){return'ui-dialog-title-'+($el.attr('id')||++this.uuid);},overlay:function(dialog){this.$el=$.ui.dialog.overlay.create(dialog);}});$.extend($.ui.dialog.overlay,{instances:[],maxZ:0,events:$.map('focus,mousedown,mouseup,keydown,keypress,click'.split(','),function(event){return event+'.dialog-overlay';}).join(' '),create:function(dialog){if(this.instances.length===0){setTimeout(function(){if($.ui.dialog.overlay.instances.length){$(document).bind($.ui.dialog.overlay.events,function(event){var dialogZ=$(event.target).parents('.ui-dialog').css('zIndex')||0;return(dialogZ>$.ui.dialog.overlay.maxZ);});}},1);$(document).bind('keydown.dialog-overlay',function(event){(dialog.options.closeOnEscape&&event.keyCode&&event.keyCode==$.ui.keyCode.ESCAPE&&dialog.close(event));});$(window).bind('resize.dialog-overlay',$.ui.dialog.overlay.resize);} +var $el=$('
                ').appendTo(document.body).addClass('ui-widget-overlay').css({width:this.width(),height:this.height()});(dialog.options.bgiframe&&$.fn.bgiframe&&$el.bgiframe());this.instances.push($el);return $el;},destroy:function($el){this.instances.splice($.inArray(this.instances,$el),1);if(this.instances.length===0){$([document,window]).unbind('.dialog-overlay');} +$el.remove();var maxZ=0;$.each(this.instances,function(){maxZ=Math.max(maxZ,this.css('z-index'));});this.maxZ=maxZ;},height:function(){if($.browser.msie&&$.browser.version<7){var scrollHeight=Math.max(document.documentElement.scrollHeight,document.body.scrollHeight);var offsetHeight=Math.max(document.documentElement.offsetHeight,document.body.offsetHeight);if(scrollHeight=0&&this.anchors[o.selected])||o.selected<0)?o.selected:0;o.disabled=$.unique(o.disabled.concat($.map(this.lis.filter('.ui-state-disabled'),function(n,i){return self.lis.index(n);}))).sort();if($.inArray(o.selected,o.disabled)!=-1){o.disabled.splice($.inArray(o.selected,o.disabled),1);} +this.panels.addClass('ui-tabs-hide');this.lis.removeClass('ui-tabs-selected ui-state-active');if(o.selected>=0&&this.anchors.length){this.panels.eq(o.selected).removeClass('ui-tabs-hide');this.lis.eq(o.selected).addClass('ui-tabs-selected ui-state-active');self.element.queue("tabs",function(){self._trigger('show',null,self._ui(self.anchors[o.selected],self.panels[o.selected]));});this.load(o.selected);} +$(window).bind('unload',function(){self.lis.add(self.anchors).unbind('.tabs');self.lis=self.anchors=self.panels=null;});} +else{o.selected=this.lis.index(this.lis.filter('.ui-tabs-selected'));} +this.element[o.collapsible?'addClass':'removeClass']('ui-tabs-collapsible');if(o.cookie){this._cookie(o.selected,o.cookie);} +for(var i=0,li;(li=this.lis[i]);i++){$(li)[$.inArray(i,o.disabled)!=-1&&!$(li).hasClass('ui-tabs-selected')?'addClass':'removeClass']('ui-state-disabled');} +if(o.cache===false){this.anchors.removeData('cache.tabs');} +this.lis.add(this.anchors).unbind('.tabs');if(o.event!='mouseover'){var addState=function(state,el){if(el.is(':not(.ui-state-disabled)')){el.addClass('ui-state-'+state);}};var removeState=function(state,el){el.removeClass('ui-state-'+state);};this.lis.bind('mouseover.tabs',function(){addState('hover',$(this));});this.lis.bind('mouseout.tabs',function(){removeState('hover',$(this));});this.anchors.bind('focus.tabs',function(){addState('focus',$(this).closest('li'));});this.anchors.bind('blur.tabs',function(){removeState('focus',$(this).closest('li'));});} +var hideFx,showFx;if(o.fx){if($.isArray(o.fx)){hideFx=o.fx[0];showFx=o.fx[1];} +else{hideFx=showFx=o.fx;}} +function resetStyle($el,fx){$el.css({display:''});if($.browser.msie&&fx.opacity){$el[0].style.removeAttribute('filter');}} +var showTab=showFx?function(clicked,$show){$(clicked).closest('li').removeClass('ui-state-default').addClass('ui-tabs-selected ui-state-active');$show.hide().removeClass('ui-tabs-hide').animate(showFx,showFx.duration||'normal',function(){resetStyle($show,showFx);self._trigger('show',null,self._ui(clicked,$show[0]));});}:function(clicked,$show){$(clicked).closest('li').removeClass('ui-state-default').addClass('ui-tabs-selected ui-state-active');$show.removeClass('ui-tabs-hide');self._trigger('show',null,self._ui(clicked,$show[0]));};var hideTab=hideFx?function(clicked,$hide){$hide.animate(hideFx,hideFx.duration||'normal',function(){self.lis.removeClass('ui-tabs-selected ui-state-active').addClass('ui-state-default');$hide.addClass('ui-tabs-hide');resetStyle($hide,hideFx);self.element.dequeue("tabs");});}:function(clicked,$hide,$show){self.lis.removeClass('ui-tabs-selected ui-state-active').addClass('ui-state-default');$hide.addClass('ui-tabs-hide');self.element.dequeue("tabs");};this.anchors.bind(o.event+'.tabs',function(){var el=this,$li=$(this).closest('li'),$hide=self.panels.filter(':not(.ui-tabs-hide)'),$show=$(self._sanitizeSelector(this.hash));if(($li.hasClass('ui-tabs-selected')&&!o.collapsible)||$li.hasClass('ui-state-disabled')||$li.hasClass('ui-state-processing')||self._trigger('select',null,self._ui(this,$show[0]))===false){this.blur();return false;} +o.selected=self.anchors.index(this);self.abort();if(o.collapsible){if($li.hasClass('ui-tabs-selected')){o.selected=-1;if(o.cookie){self._cookie(o.selected,o.cookie);} +self.element.queue("tabs",function(){hideTab(el,$hide);}).dequeue("tabs");this.blur();return false;} +else if(!$hide.length){if(o.cookie){self._cookie(o.selected,o.cookie);} +self.element.queue("tabs",function(){showTab(el,$show);});self.load(self.anchors.index(this));this.blur();return false;}} +if(o.cookie){self._cookie(o.selected,o.cookie);} +if($show.length){if($hide.length){self.element.queue("tabs",function(){hideTab(el,$hide);});} +self.element.queue("tabs",function(){showTab(el,$show);});self.load(self.anchors.index(this));} +else{throw'jQuery UI Tabs: Mismatching fragment identifier.';} +if($.browser.msie){this.blur();}});this.anchors.bind('click.tabs',function(){return false;});},destroy:function(){var o=this.options;this.abort();this.element.unbind('.tabs').removeClass('ui-tabs ui-widget ui-widget-content ui-corner-all ui-tabs-collapsible').removeData('tabs');this.list.removeClass('ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all');this.anchors.each(function(){var href=$.data(this,'href.tabs');if(href){this.href=href;} +var $this=$(this).unbind('.tabs');$.each(['href','load','cache'],function(i,prefix){$this.removeData(prefix+'.tabs');});});this.lis.unbind('.tabs').add(this.panels).each(function(){if($.data(this,'destroy.tabs')){$(this).remove();} +else{$(this).removeClass(['ui-state-default','ui-corner-top','ui-tabs-selected','ui-state-active','ui-state-hover','ui-state-focus','ui-state-disabled','ui-tabs-panel','ui-widget-content','ui-corner-bottom','ui-tabs-hide'].join(' '));}});if(o.cookie){this._cookie(null,o.cookie);}},add:function(url,label,index){if(index===undefined){index=this.anchors.length;} +var self=this,o=this.options,$li=$(o.tabTemplate.replace(/#\{href\}/g,url).replace(/#\{label\}/g,label)),id=!url.indexOf('#')?url.replace('#',''):this._tabId($('a',$li)[0]);$li.addClass('ui-state-default ui-corner-top').data('destroy.tabs',true);var $panel=$('#'+id);if(!$panel.length){$panel=$(o.panelTemplate).attr('id',id).data('destroy.tabs',true);} +$panel.addClass('ui-tabs-panel ui-widget-content ui-corner-bottom ui-tabs-hide');if(index>=this.lis.length){$li.appendTo(this.list);$panel.appendTo(this.list[0].parentNode);} +else{$li.insertBefore(this.lis[index]);$panel.insertBefore(this.panels[index]);} +o.disabled=$.map(o.disabled,function(n,i){return n>=index?++n:n;});this._tabify();if(this.anchors.length==1){$li.addClass('ui-tabs-selected ui-state-active');$panel.removeClass('ui-tabs-hide');this.element.queue("tabs",function(){self._trigger('show',null,self._ui(self.anchors[0],self.panels[0]));});this.load(0);} +this._trigger('add',null,this._ui(this.anchors[index],this.panels[index]));},remove:function(index){var o=this.options,$li=this.lis.eq(index).remove(),$panel=this.panels.eq(index).remove();if($li.hasClass('ui-tabs-selected')&&this.anchors.length>1){this.select(index+(index+1=index?--n:n;});this._tabify();this._trigger('remove',null,this._ui($li.find('a')[0],$panel[0]));},enable:function(index){var o=this.options;if($.inArray(index,o.disabled)==-1){return;} +this.lis.eq(index).removeClass('ui-state-disabled');o.disabled=$.grep(o.disabled,function(n,i){return n!=index;});this._trigger('enable',null,this._ui(this.anchors[index],this.panels[index]));},disable:function(index){var self=this,o=this.options;if(index!=o.selected){this.lis.eq(index).addClass('ui-state-disabled');o.disabled.push(index);o.disabled.sort();this._trigger('disable',null,this._ui(this.anchors[index],this.panels[index]));}},select:function(index){if(typeof index=='string'){index=this.anchors.index(this.anchors.filter('[href$='+index+']'));} +else if(index===null){index=-1;} +if(index==-1&&this.options.collapsible){index=this.options.selected;} +this.anchors.eq(index).trigger(this.options.event+'.tabs');},load:function(index){var self=this,o=this.options,a=this.anchors.eq(index)[0],url=$.data(a,'load.tabs');this.abort();if(!url||this.element.queue("tabs").length!==0&&$.data(a,'cache.tabs')){this.element.dequeue("tabs");return;} +this.lis.eq(index).addClass('ui-state-processing');if(o.spinner){var span=$('span',a);span.data('label.tabs',span.html()).html(o.spinner);} +this.xhr=$.ajax($.extend({},o.ajaxOptions,{url:url,success:function(r,s){$(self._sanitizeSelector(a.hash)).html(r);self._cleanup();if(o.cache){$.data(a,'cache.tabs',true);} +self._trigger('load',null,self._ui(self.anchors[index],self.panels[index]));try{o.ajaxOptions.success(r,s);} +catch(e){} +self.element.dequeue("tabs");}}));},abort:function(){this.element.queue([]);this.panels.stop(false,true);if(this.xhr){this.xhr.abort();delete this.xhr;} +this._cleanup();},url:function(index,url){this.anchors.eq(index).removeData('cache.tabs').data('load.tabs',url);},length:function(){return this.anchors.length;}});$.extend($.ui.tabs,{version:'1.7.2',getter:'length',defaults:{ajaxOptions:null,cache:false,cookie:null,collapsible:false,disabled:[],event:'click',fx:null,idPrefix:'ui-tabs-',panelTemplate:'
                ',spinner:'Loading…',tabTemplate:'
              • #{label}
              • '}});$.extend($.ui.tabs.prototype,{rotation:null,rotate:function(ms,continuing){var self=this,o=this.options;var rotate=self._rotate||(self._rotate=function(e){clearTimeout(self.rotation);self.rotation=setTimeout(function(){var t=o.selected;self.select(++t
                ').appendTo(this.element);this._refreshValue();},destroy:function(){this.element.removeClass("ui-progressbar" ++" ui-widget" ++" ui-widget-content" ++" ui-corner-all").removeAttr("role").removeAttr("aria-valuemin").removeAttr("aria-valuemax").removeAttr("aria-valuenow").removeData("progressbar").unbind(".progressbar");this.valueDiv.remove();$.widget.prototype.destroy.apply(this,arguments);},value:function(newValue){if(newValue===undefined){return this._value();} +this._setData('value',newValue);return this;},_setData:function(key,value){switch(key){case'value':this.options.value=value;this._refreshValue();this._trigger('change',null,{});break;} +$.widget.prototype._setData.apply(this,arguments);},_value:function(){var val=this.options.value;if(valthis._valueMax())val=this._valueMax();return val;},_valueMin:function(){var valueMin=0;return valueMin;},_valueMax:function(){var valueMax=100;return valueMax;},_refreshValue:function(){var value=this.value();this.valueDiv[value==this._valueMax()?'addClass':'removeClass']("ui-corner-right");this.valueDiv.width(value+'%');this.element.attr("aria-valuenow",value);}});$.extend($.ui.progressbar,{version:"1.7.2",defaults:{value:0}});})(jQuery);;jQuery.effects||(function($){$.effects={version:"1.7.2",save:function(element,set){for(var i=0;i');var wrapper=element.parent();if(element.css('position')=='static'){wrapper.css({position:'relative'});element.css({position:'relative'});}else{var top=element.css('top');if(isNaN(parseInt(top,10)))top='auto';var left=element.css('left');if(isNaN(parseInt(left,10)))left='auto';wrapper.css({position:element.css('position'),top:top,left:left,zIndex:element.css('z-index')}).show();element.css({position:'relative',top:0,left:0});} +wrapper.css(props);return wrapper;},removeWrapper:function(element){if(element.parent().is('.ui-effects-wrapper')) +return element.parent().replaceWith(element);return element;},setTransition:function(element,list,factor,value){value=value||{};$.each(list,function(i,x){unit=element.cssUnit(x);if(unit[0]>0)value[x]=unit[0]*factor+unit[1];});return value;},animateClass:function(value,duration,easing,callback){var cb=(typeof easing=="function"?easing:(callback?callback:null));var ea=(typeof easing=="string"?easing:null);return this.each(function(){var offset={};var that=$(this);var oldStyleAttr=that.attr("style")||'';if(typeof oldStyleAttr=='object')oldStyleAttr=oldStyleAttr["cssText"];if(value.toggle){that.hasClass(value.toggle)?value.remove=value.toggle:value.add=value.toggle;} +var oldStyle=$.extend({},(document.defaultView?document.defaultView.getComputedStyle(this,null):this.currentStyle));if(value.add)that.addClass(value.add);if(value.remove)that.removeClass(value.remove);var newStyle=$.extend({},(document.defaultView?document.defaultView.getComputedStyle(this,null):this.currentStyle));if(value.add)that.removeClass(value.add);if(value.remove)that.addClass(value.remove);for(var n in newStyle){if(typeof newStyle[n]!="function"&&newStyle[n]&&n.indexOf("Moz")==-1&&n.indexOf("length")==-1&&newStyle[n]!=oldStyle[n]&&(n.match(/color/i)||(!n.match(/color/i)&&!isNaN(parseInt(newStyle[n],10))))&&(oldStyle.position!="static"||(oldStyle.position=="static"&&!n.match(/left|top|bottom|right/))))offset[n]=newStyle[n];} +that.animate(offset,duration,ea,function(){if(typeof $(this).attr("style")=='object'){$(this).attr("style")["cssText"]="";$(this).attr("style")["cssText"]=oldStyleAttr;}else $(this).attr("style",oldStyleAttr);if(value.add)$(this).addClass(value.add);if(value.remove)$(this).removeClass(value.remove);if(cb)cb.apply(this,arguments);});});}};function _normalizeArguments(a,m){var o=a[1]&&a[1].constructor==Object?a[1]:{};if(m)o.mode=m;var speed=a[1]&&a[1].constructor!=Object?a[1]:(o.duration?o.duration:a[2]);speed=$.fx.off?0:typeof speed==="number"?speed:$.fx.speeds[speed]||$.fx.speeds._default;var callback=o.callback||($.isFunction(a[1])&&a[1])||($.isFunction(a[2])&&a[2])||($.isFunction(a[3])&&a[3]);return[a[0],o,speed,callback];} +$.fn.extend({_show:$.fn.show,_hide:$.fn.hide,__toggle:$.fn.toggle,_addClass:$.fn.addClass,_removeClass:$.fn.removeClass,_toggleClass:$.fn.toggleClass,effect:function(fx,options,speed,callback){return $.effects[fx]?$.effects[fx].call(this,{method:fx,options:options||{},duration:speed,callback:callback}):null;},show:function(){if(!arguments[0]||(arguments[0].constructor==Number||(/(slow|normal|fast)/).test(arguments[0]))) +return this._show.apply(this,arguments);else{return this.effect.apply(this,_normalizeArguments(arguments,'show'));}},hide:function(){if(!arguments[0]||(arguments[0].constructor==Number||(/(slow|normal|fast)/).test(arguments[0]))) +return this._hide.apply(this,arguments);else{return this.effect.apply(this,_normalizeArguments(arguments,'hide'));}},toggle:function(){if(!arguments[0]||(arguments[0].constructor==Number||(/(slow|normal|fast)/).test(arguments[0]))||($.isFunction(arguments[0])||typeof arguments[0]=='boolean')){return this.__toggle.apply(this,arguments);}else{return this.effect.apply(this,_normalizeArguments(arguments,'toggle'));}},addClass:function(classNames,speed,easing,callback){return speed?$.effects.animateClass.apply(this,[{add:classNames},speed,easing,callback]):this._addClass(classNames);},removeClass:function(classNames,speed,easing,callback){return speed?$.effects.animateClass.apply(this,[{remove:classNames},speed,easing,callback]):this._removeClass(classNames);},toggleClass:function(classNames,speed,easing,callback){return((typeof speed!=="boolean")&&speed)?$.effects.animateClass.apply(this,[{toggle:classNames},speed,easing,callback]):this._toggleClass(classNames,speed);},morph:function(remove,add,speed,easing,callback){return $.effects.animateClass.apply(this,[{add:add,remove:remove},speed,easing,callback]);},switchClass:function(){return this.morph.apply(this,arguments);},cssUnit:function(key){var style=this.css(key),val=[];$.each(['em','px','%','pt'],function(i,unit){if(style.indexOf(unit)>0) +val=[parseFloat(style),unit];});return val;}});$.each(['backgroundColor','borderBottomColor','borderLeftColor','borderRightColor','borderTopColor','color','outlineColor'],function(i,attr){$.fx.step[attr]=function(fx){if(fx.state==0){fx.start=getColor(fx.elem,attr);fx.end=getRGB(fx.end);} +fx.elem.style[attr]="rgb("+[Math.max(Math.min(parseInt((fx.pos*(fx.end[0]-fx.start[0]))+fx.start[0],10),255),0),Math.max(Math.min(parseInt((fx.pos*(fx.end[1]-fx.start[1]))+fx.start[1],10),255),0),Math.max(Math.min(parseInt((fx.pos*(fx.end[2]-fx.start[2]))+fx.start[2],10),255),0)].join(",")+")";};});function getRGB(color){var result;if(color&&color.constructor==Array&&color.length==3) +return color;if(result=/rgb\(\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*\)/.exec(color)) +return[parseInt(result[1],10),parseInt(result[2],10),parseInt(result[3],10)];if(result=/rgb\(\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*\)/.exec(color)) +return[parseFloat(result[1])*2.55,parseFloat(result[2])*2.55,parseFloat(result[3])*2.55];if(result=/#([a-fA-F0-9]{2})([a-fA-F0-9]{2})([a-fA-F0-9]{2})/.exec(color)) +return[parseInt(result[1],16),parseInt(result[2],16),parseInt(result[3],16)];if(result=/#([a-fA-F0-9])([a-fA-F0-9])([a-fA-F0-9])/.exec(color)) +return[parseInt(result[1]+result[1],16),parseInt(result[2]+result[2],16),parseInt(result[3]+result[3],16)];if(result=/rgba\(0, 0, 0, 0\)/.exec(color)) +return colors['transparent'];return colors[$.trim(color).toLowerCase()];} +function getColor(elem,attr){var color;do{color=$.curCSS(elem,attr);if(color!=''&&color!='transparent'||$.nodeName(elem,"body")) +break;attr="backgroundColor";}while(elem=elem.parentNode);return getRGB(color);};var colors={aqua:[0,255,255],azure:[240,255,255],beige:[245,245,220],black:[0,0,0],blue:[0,0,255],brown:[165,42,42],cyan:[0,255,255],darkblue:[0,0,139],darkcyan:[0,139,139],darkgrey:[169,169,169],darkgreen:[0,100,0],darkkhaki:[189,183,107],darkmagenta:[139,0,139],darkolivegreen:[85,107,47],darkorange:[255,140,0],darkorchid:[153,50,204],darkred:[139,0,0],darksalmon:[233,150,122],darkviolet:[148,0,211],fuchsia:[255,0,255],gold:[255,215,0],green:[0,128,0],indigo:[75,0,130],khaki:[240,230,140],lightblue:[173,216,230],lightcyan:[224,255,255],lightgreen:[144,238,144],lightgrey:[211,211,211],lightpink:[255,182,193],lightyellow:[255,255,224],lime:[0,255,0],magenta:[255,0,255],maroon:[128,0,0],navy:[0,0,128],olive:[128,128,0],orange:[255,165,0],pink:[255,192,203],purple:[128,0,128],violet:[128,0,128],red:[255,0,0],silver:[192,192,192],white:[255,255,255],yellow:[255,255,0],transparent:[255,255,255]};$.easing.jswing=$.easing.swing;$.extend($.easing,{def:'easeOutQuad',swing:function(x,t,b,c,d){return $.easing[$.easing.def](x,t,b,c,d);},easeInQuad:function(x,t,b,c,d){return c*(t/=d)*t+b;},easeOutQuad:function(x,t,b,c,d){return-c*(t/=d)*(t-2)+b;},easeInOutQuad:function(x,t,b,c,d){if((t/=d/2)<1)return c/2*t*t+b;return-c/2*((--t)*(t-2)-1)+b;},easeInCubic:function(x,t,b,c,d){return c*(t/=d)*t*t+b;},easeOutCubic:function(x,t,b,c,d){return c*((t=t/d-1)*t*t+1)+b;},easeInOutCubic:function(x,t,b,c,d){if((t/=d/2)<1)return c/2*t*t*t+b;return c/2*((t-=2)*t*t+2)+b;},easeInQuart:function(x,t,b,c,d){return c*(t/=d)*t*t*t+b;},easeOutQuart:function(x,t,b,c,d){return-c*((t=t/d-1)*t*t*t-1)+b;},easeInOutQuart:function(x,t,b,c,d){if((t/=d/2)<1)return c/2*t*t*t*t+b;return-c/2*((t-=2)*t*t*t-2)+b;},easeInQuint:function(x,t,b,c,d){return c*(t/=d)*t*t*t*t+b;},easeOutQuint:function(x,t,b,c,d){return c*((t=t/d-1)*t*t*t*t+1)+b;},easeInOutQuint:function(x,t,b,c,d){if((t/=d/2)<1)return c/2*t*t*t*t*t+b;return c/2*((t-=2)*t*t*t*t+2)+b;},easeInSine:function(x,t,b,c,d){return-c*Math.cos(t/d*(Math.PI/2))+c+b;},easeOutSine:function(x,t,b,c,d){return c*Math.sin(t/d*(Math.PI/2))+b;},easeInOutSine:function(x,t,b,c,d){return-c/2*(Math.cos(Math.PI*t/d)-1)+b;},easeInExpo:function(x,t,b,c,d){return(t==0)?b:c*Math.pow(2,10*(t/d-1))+b;},easeOutExpo:function(x,t,b,c,d){return(t==d)?b+c:c*(-Math.pow(2,-10*t/d)+1)+b;},easeInOutExpo:function(x,t,b,c,d){if(t==0)return b;if(t==d)return b+c;if((t/=d/2)<1)return c/2*Math.pow(2,10*(t-1))+b;return c/2*(-Math.pow(2,-10*--t)+2)+b;},easeInCirc:function(x,t,b,c,d){return-c*(Math.sqrt(1-(t/=d)*t)-1)+b;},easeOutCirc:function(x,t,b,c,d){return c*Math.sqrt(1-(t=t/d-1)*t)+b;},easeInOutCirc:function(x,t,b,c,d){if((t/=d/2)<1)return-c/2*(Math.sqrt(1-t*t)-1)+b;return c/2*(Math.sqrt(1-(t-=2)*t)+1)+b;},easeInElastic:function(x,t,b,c,d){var s=1.70158;var p=0;var a=c;if(t==0)return b;if((t/=d)==1)return b+c;if(!p)p=d*.3;if(a').appendTo(document.body).addClass(o.options.className).css({top:startPosition.top,left:startPosition.left,height:elem.innerHeight(),width:elem.innerWidth(),position:'absolute'}).animate(animation,o.duration,o.options.easing,function(){transfer.remove();(o.callback&&o.callback.apply(elem[0],arguments));elem.dequeue();});});};})(jQuery); \ No newline at end of file -- cgit v1.2.3 From 1d40c77c4c05a85fbf6bbb96820fb98cbaa989eb Mon Sep 17 00:00:00 2001 From: Tim Almdal Date: Sat, 12 Sep 2009 08:53:24 -0700 Subject: Update the organize module to use the release version of jquery Selectable. Unfortunately this does not have the functionality to select additional thumbnails using the ctrl or alt-keys, it is preferable to forking the Selectable component. This functionality should arrive with ui.jquery 1.8.x --- modules/organize/css/organize.css | 5 +++-- modules/organize/js/organize.js | 8 ++++---- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/modules/organize/css/organize.css b/modules/organize/css/organize.css index 15b5538d..b1cef33c 100644 --- a/modules/organize/css/organize.css +++ b/modules/organize/css/organize.css @@ -102,12 +102,13 @@ width: 9em; } -.gOrganizeMicroThumbGridCell.ui-state-selected { +.gOrganizeMicroThumbGridCell.ui-selecting, +.gOrganizeMicroThumbGridCell.ui-selected { margin: 2px; border: 2px solid #13A; } -.ui-selectable-lasso { +.ui-selectable-helper { z-index: 2000 !important; border: 1px dashed #00F; opacity: 0.25; diff --git a/modules/organize/js/organize.js b/modules/organize/js/organize.js index c30f89e0..7d204708 100644 --- a/modules/organize/js/organize.js +++ b/modules/organize/js/organize.js @@ -1,12 +1,12 @@ (function($) { $.organize = { micro_thumb_draggable: { - handle: ".ui-state-selected", + handle: ".ui-selected", distance: 10, cursorAt: { left: -10, top: -10}, appendTo: "#gOrganizeMicroThumbPanel", helper: function(event, ui) { - var selected = $(".ui-draggable.ui-state-selected img"); + var selected = $(".ui-draggable.ui-selected img"); if (selected.length) { var set = $('
                ') .css({ @@ -37,7 +37,7 @@ }, start: function(event, ui) { - $("#gOrganizeMicroThumbPanel .ui-state-selected").hide(); + $("#gOrganizeMicroThumbPanel .ui-selected").hide(); }, drag: function(event, ui) { @@ -80,7 +80,7 @@ greedy: true, drop: function(event, ui) { if ($(event.target).hasClass("gViewOnly")) { - $(".ui-state-selected").show(); + $(".ui-selected").show(); $(".gOrganizeMicroThumbGridCell").css("borderStyle", "none"); } else { $.organize.do_drop({ -- cgit v1.2.3 From 0bb489b69438266359bfd22955f4d5c8f9d6ade3 Mon Sep 17 00:00:00 2001 From: Bharat Mediratta Date: Sat, 12 Sep 2009 10:02:27 -0700 Subject: Properly internationalize the text for the By: line. This gets rid of the escaping problem. --- modules/info/helpers/info_theme.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/modules/info/helpers/info_theme.php b/modules/info/helpers/info_theme.php index 51378e54..e5f9c909 100644 --- a/modules/info/helpers/info_theme.php +++ b/modules/info/helpers/info_theme.php @@ -38,7 +38,9 @@ class info_theme_Core { if ($item->owner) { $results .= "
              • "; if ($item->owner->url) { - $results .= t("By: %owner_name", array("owner_name" => "owner->url}\">{$item->owner->full_name}")); + $results .= t("By: %owner_name", + array("owner_name" => $item->owner->display_name(), + "owner_url" => $item->owner->url)); } else { $results .= t("By: %owner_name", array("owner_name" => "{$item->owner->full_name}")); } -- cgit v1.2.3 From 961bc3b18571b5f3ad2a355b71d40c4830dd44ba Mon Sep 17 00:00:00 2001 From: Bharat Mediratta Date: Sat, 12 Sep 2009 10:06:24 -0700 Subject: Use user::display_name() in another case where it was missing. --- modules/info/helpers/info_theme.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/info/helpers/info_theme.php b/modules/info/helpers/info_theme.php index e5f9c909..4bf894ad 100644 --- a/modules/info/helpers/info_theme.php +++ b/modules/info/helpers/info_theme.php @@ -42,7 +42,7 @@ class info_theme_Core { array("owner_name" => $item->owner->display_name(), "owner_url" => $item->owner->url)); } else { - $results .= t("By: %owner_name", array("owner_name" => "{$item->owner->full_name}")); + $results .= t("By: %owner_name", array("owner_name" => $item->owner->display_name())); } $results .= "
              • "; } -- cgit v1.2.3 From 823fa2fc8339a6638ef4f0fcdae7f96e99a4f0bd Mon Sep 17 00:00:00 2001 From: Bharat Mediratta Date: Sat, 12 Sep 2009 10:33:46 -0700 Subject: Updated for url format changes applied in 2aad580f53dbc06bb170c710467b47a5a532c6c8. --- modules/gallery/tests/xss_data.txt | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/modules/gallery/tests/xss_data.txt b/modules/gallery/tests/xss_data.txt index 8c71740e..193d2ca1 100644 --- a/modules/gallery/tests/xss_data.txt +++ b/modules/gallery/tests/xss_data.txt @@ -48,6 +48,7 @@ modules/gallery/views/admin_block_log_entries.html.php 8 DIRTY $entry modules/gallery/views/admin_block_news.html.php 5 DIRTY_JS $entry["link"] modules/gallery/views/admin_block_news.html.php 5 DIRTY $entry["title"] modules/gallery/views/admin_block_news.html.php 7 DIRTY text::limit_words(strip_tags($entry["description"]),25); +modules/gallery/views/admin_block_photo_stream.html.php 5 DIRTY_JS $photo->url() 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 @@ -180,14 +181,14 @@ modules/image_block/views/image_block_block.html.php 3 DIRTY_JS $item- modules/image_block/views/image_block_block.html.php 4 DIRTY $item->thumb_img(array("class"=>"gThumbnail")) modules/info/views/info_block.html.php 22 DIRTY date("M j, Y H:i:s",$item->captured) modules/info/views/info_block.html.php 29 DIRTY_JS $item->owner->url -modules/notification/views/comment_published.html.php 28 DIRTY_JS $comment->item()->url(array(),true) -modules/notification/views/comment_published.html.php 29 DIRTY $comment->item()->url(array(),true) -modules/notification/views/item_added.html.php 16 DIRTY_JS $item->url(array(),true) -modules/notification/views/item_added.html.php 17 DIRTY $item->url(array(),true) -modules/notification/views/item_deleted.html.php 18 DIRTY_JS $item->parent()->url(array(),true) -modules/notification/views/item_deleted.html.php 19 DIRTY $item->parent()->url(array(),true) -modules/notification/views/item_updated.html.php 20 DIRTY_JS $item->url(array(),true) -modules/notification/views/item_updated.html.php 20 DIRTY $item->url(array(),true) +modules/notification/views/comment_published.html.php 28 DIRTY_JS $comment->item()->abs_url() +modules/notification/views/comment_published.html.php 29 DIRTY $comment->item()->abs_url() +modules/notification/views/item_added.html.php 16 DIRTY_JS $item->abs_url() +modules/notification/views/item_added.html.php 17 DIRTY $item->abs_url() +modules/notification/views/item_deleted.html.php 18 DIRTY_JS $item->parent()->abs_url() +modules/notification/views/item_deleted.html.php 19 DIRTY $item->parent()->abs_url() +modules/notification/views/item_updated.html.php 20 DIRTY_JS $item->abs_url() +modules/notification/views/item_updated.html.php 20 DIRTY $item->abs_url() modules/organize/views/organize_dialog.html.php 3 DIRTY_JS url::site("organize/move_to/__ALBUM_ID__?csrf=$csrf") modules/organize/views/organize_dialog.html.php 4 DIRTY_JS url::site("organize/rearrange/__TARGET_ID__/__BEFORE__?csrf=$csrf") modules/organize/views/organize_dialog.html.php 5 DIRTY_JS url::site("organize/sort_order/__ALBUM_ID__/__COL__/__DIR__?csrf=$csrf") @@ -246,6 +247,7 @@ modules/rss/views/feed.mrss.php 73 DIRTY_ATTR $chi modules/rss/views/feed.mrss.php 74 DIRTY_ATTR $child->mime_type modules/rss/views/rss_block.html.php 6 DIRTY_JS rss::url($url) modules/search/views/search.html.php 30 DIRTY_ATTR $item_class +modules/search/views/search.html.php 31 DIRTY_JS $item->url() modules/search/views/search.html.php 32 DIRTY $item->thumb_img() modules/server_add/views/admin_server_add.html.php 15 DIRTY_ATTR $id modules/server_add/views/admin_server_add.html.php 24 DIRTY $form @@ -285,6 +287,7 @@ themes/admin_default/views/admin.html.php 15 DIRTY_JS $theme themes/admin_default/views/admin.html.php 32 DIRTY $theme->admin_head() themes/admin_default/views/admin.html.php 36 DIRTY $theme->admin_page_top() themes/admin_default/views/admin.html.php 44 DIRTY $theme->admin_header_top() +themes/admin_default/views/admin.html.php 49 DIRTY_JS item::root()->url() themes/admin_default/views/admin.html.php 53 DIRTY $theme->admin_menu() themes/admin_default/views/admin.html.php 55 DIRTY $theme->admin_header_bottom() themes/admin_default/views/admin.html.php 62 DIRTY $content @@ -325,6 +328,8 @@ themes/default/views/page.html.php 41 DIRTY $new_w themes/default/views/page.html.php 42 DIRTY $new_height themes/default/views/page.html.php 43 DIRTY $thumb_proportion themes/default/views/page.html.php 82 DIRTY $header_text +themes/default/views/page.html.php 84 DIRTY_JS item::root()->url() +themes/default/views/page.html.php 98 DIRTY_JS $parent->url("show={$theme->item()->id}") themes/default/views/page.html.php 112 DIRTY $content themes/default/views/page.html.php 118 DIRTY newView("sidebar.html") themes/default/views/page.html.php 125 DIRTY $footer_text -- cgit v1.2.3 From 711cdde5b9755140981000adc6dd7897d836ccc5 Mon Sep 17 00:00:00 2001 From: Bharat Mediratta Date: Sat, 12 Sep 2009 20:46:54 -0700 Subject: Only tack ?show= on for the last parent, because that's the only parent for which the id is relevant. In a perfect world each parent's link would have a ?show= for the next child's id. But that would require some confusing code and I don't want to put that into the default/example theme yet. --- themes/default/views/page.html.php | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/themes/default/views/page.html.php b/themes/default/views/page.html.php index 733534ea..19d8cc00 100644 --- a/themes/default/views/page.html.php +++ b/themes/default/views/page.html.php @@ -95,7 +95,12 @@
                • - item()->id}") ?>"> + + item()->id}" : null) ?>"> title) ?>
                • -- cgit v1.2.3 From caa2002d7777e0ceb884d4c628650804620ca2b6 Mon Sep 17 00:00:00 2001 From: Bharat Mediratta Date: Sun, 13 Sep 2009 01:04:16 -0700 Subject: If there's a show= param and we can't find the given id in the current album, just ignore the parameter. --- modules/gallery/controllers/albums.php | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/modules/gallery/controllers/albums.php b/modules/gallery/controllers/albums.php index 183c26d0..08a60132 100644 --- a/modules/gallery/controllers/albums.php +++ b/modules/gallery/controllers/albums.php @@ -40,11 +40,13 @@ class Albums_Controller extends Items_Controller { if ($show) { $index = $album->get_position($show); - $page = ceil($index / $page_size); - if ($page == 1) { - url::redirect($album->abs_url()); - } else { - url::redirect($album->abs_url("page=$page")); + if ($index) { + $page = ceil($index / $page_size); + if ($page == 1) { + url::redirect($album->abs_url()); + } else { + url::redirect($album->abs_url("page=$page")); + } } } -- cgit v1.2.3
                @@ -21,7 +21,7 @@
                name ?>
                "> updated) ?>
                "> updated) ?>
                - - url(array(), true) ?> + + abs_url() ?>
                url(array(), true) ?>abs_url() ?>