summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChristian Weiske <cweiske@cweiske.de>2011-04-06 19:13:19 +0200
committerChristian Weiske <cweiske@cweiske.de>2011-04-06 19:13:19 +0200
commit7379805565815c576723b888a20af080248222da (patch)
tree498c98e8b6c43c2729349b7680c6a20efcfb98f3
parent1e3cd8bf6ee636a5af692b57906612d6109849cb (diff)
parent12c77161aca2c7d76fa5154fa1f4e214106d834b (diff)
downloadSemanticScuttle-origin/quickform.zip
SemanticScuttle-origin/quickform.tar.gz
SemanticScuttle-origin/quickform.tar.bz2
Merge branch 'master' into quickformorigin/quickform
Conflicts: data/templates/bookmarks.tpl.php data/templates/sidebar.block.search.php data/templates/top.inc.php doc/developers/TODO src/SemanticScuttle/header.php
-rw-r--r--.gitignore2
-rw-r--r--build.properties.dist1
-rw-r--r--build.xml239
-rw-r--r--data/config.default.php12
-rw-r--r--data/config.php.dist2
-rw-r--r--data/locales/de_DE/LC_MESSAGES/messages.mobin29546 -> 29547 bytes
-rw-r--r--data/locales/de_DE/LC_MESSAGES/messages.po2
-rw-r--r--data/locales/fr_CA/LC_MESSAGES/messages.po1875
-rw-r--r--data/locales/fr_FR/LC_MESSAGES/messages.po596
-rw-r--r--data/locales/messages.po134
-rw-r--r--data/templates/admin.tpl.php2
-rw-r--r--data/templates/bookmarkcommondescriptionedit.tpl.php3
-rw-r--r--data/templates/bookmarklet.inc.php117
-rw-r--r--data/templates/bookmarks.tpl.php162
-rw-r--r--data/templates/dynamictags.inc.php73
-rw-r--r--data/templates/editbookmark.tpl.php153
-rw-r--r--data/templates/editprofile.tpl.php8
-rw-r--r--data/templates/sidebar.block.linked.php133
-rw-r--r--data/templates/sidebar.block.menu.php6
-rw-r--r--data/templates/sidebar.block.menu2.php71
-rw-r--r--data/templates/sidebar.block.recent.php2
-rw-r--r--data/templates/sidebar.block.search.php45
-rw-r--r--data/templates/sidebar.block.users.php4
-rw-r--r--data/templates/sidebar.block.watchlist.php8
-rw-r--r--data/templates/tag2tagadd.tpl.php2
-rw-r--r--data/templates/tagcommondescriptionedit.tpl.php3
-rw-r--r--data/templates/tagrename.tpl.php4
-rw-r--r--data/templates/top.inc.php22
-rw-r--r--data/templates/users.tpl.php9
-rw-r--r--doc/ChangeLog29
-rw-r--r--doc/developers/TODO5
-rw-r--r--doc/developers/api10
-rw-r--r--doc/developers/doc-TODO9
-rw-r--r--doc/developers/release-new-version4
-rw-r--r--doc/developers/translation2
-rw-r--r--html.properties1
-rw-r--r--scripts/database-dump.php26
-rw-r--r--scripts/database-restore.php37
-rw-r--r--src/SemanticScuttle/Model/RemoteUser.php48
-rw-r--r--src/SemanticScuttle/Model/User.php5
-rw-r--r--src/SemanticScuttle/Model/UserArray.php41
-rw-r--r--src/SemanticScuttle/Service/Bookmark.php169
-rw-r--r--src/SemanticScuttle/Service/Bookmark2Tag.php167
-rw-r--r--src/SemanticScuttle/Service/SearchHistory.php195
-rw-r--r--src/SemanticScuttle/Service/Tag2Tag.php45
-rw-r--r--src/SemanticScuttle/Service/User.php31
-rw-r--r--src/SemanticScuttle/constants.php77
-rw-r--r--src/SemanticScuttle/db/mysqli.php2
-rw-r--r--src/SemanticScuttle/header.php45
-rw-r--r--src/php-gettext/Makefile14
-rw-r--r--src/php-gettext/README74
-rw-r--r--src/php-gettext/examples/locale/sr_CS/LC_MESSAGES/messages.mobin834 -> 829 bytes
-rw-r--r--src/php-gettext/examples/locale/sr_CS/LC_MESSAGES/messages.po3
-rw-r--r--src/php-gettext/examples/pigs_dropin.php10
-rw-r--r--src/php-gettext/examples/pigs_fallback.php10
-rw-r--r--src/php-gettext/examples/update4
-rw-r--r--src/php-gettext/gettext.inc478
-rw-r--r--src/php-gettext/gettext.php179
-rw-r--r--src/php-gettext/streams.php32
-rw-r--r--src/php-gettext/tests/LocalesTest.php66
-rw-r--r--src/php-gettext/tests/ParsingTest.php43
-rw-r--r--tests/AllTests.php7
-rw-r--r--tests/Api/PostsAddTest.php435
-rw-r--r--tests/Api/PostsDeleteTest.php303
-rw-r--r--tests/Api/PostsUpdateTest.php135
-rw-r--r--tests/Bookmark2TagTest.php452
-rw-r--r--tests/BookmarkTest.php145
-rw-r--r--tests/CommonDescriptionTest.php5
-rw-r--r--tests/SearchHistoryTest.php393
-rw-r--r--tests/Tag2TagTest.php5
-rw-r--r--tests/TagTest.php5
-rw-r--r--tests/TagsCacheTest.php8
-rw-r--r--tests/TestBase.php56
-rw-r--r--tests/TestBaseApi.php137
-rw-r--r--tests/UserArrayTest.php68
-rw-r--r--tests/UserTest.php9
-rw-r--r--tests/VoteTest.php5
-rw-r--r--tests/ajax/GetAdminLinkedTagsTest.php146
-rw-r--r--tests/ajax/GetAdminTagsTest.php122
-rw-r--r--tests/ajax/GetContactTagsTest.php102
-rw-r--r--tests/phpunit.xml8
-rw-r--r--tests/prepare.php8
-rw-r--r--www/ajax/getadminlinkedtags.php132
-rw-r--r--www/ajax/getadmintags.php81
-rw-r--r--www/ajax/getcontacttags.php79
-rw-r--r--www/ajax/getlinkedtags.php178
-rw-r--r--www/api/export_html.php2
-rw-r--r--www/api/httpauth.inc.php31
-rw-r--r--www/api/posts_add.php151
-rw-r--r--www/api/posts_delete.php62
-rw-r--r--www/api/posts_update.php46
-rw-r--r--www/bookmarks.php11
-rw-r--r--www/gsearch/index.php4
-rw-r--r--www/js/jquery-ui-1.8.11/jquery.ui.autocomplete.js612
-rw-r--r--www/js/jquery-ui-1.8.11/jquery.ui.autocomplete.min.js32
-rw-r--r--www/js/jquery-ui-1.8.11/jquery.ui.core.js308
-rw-r--r--www/js/jquery-ui-1.8.11/jquery.ui.core.min.js17
-rw-r--r--www/js/jquery-ui-1.8.11/jquery.ui.position.js252
-rw-r--r--www/js/jquery-ui-1.8.11/jquery.ui.position.min.js16
-rw-r--r--www/js/jquery-ui-1.8.11/jquery.ui.widget.js262
-rw-r--r--www/js/jquery-ui-1.8.11/jquery.ui.widget.min.js15
-rw-r--r--www/js/jquery-ui-1.8.11/themes/base/images/ui-bg_flat_0_aaaaaa_40x100.pngbin0 -> 180 bytes
-rw-r--r--www/js/jquery-ui-1.8.11/themes/base/images/ui-bg_flat_75_ffffff_40x100.pngbin0 -> 178 bytes
-rw-r--r--www/js/jquery-ui-1.8.11/themes/base/images/ui-bg_glass_55_fbf9ee_1x400.pngbin0 -> 120 bytes
-rw-r--r--www/js/jquery-ui-1.8.11/themes/base/images/ui-bg_glass_65_ffffff_1x400.pngbin0 -> 105 bytes
-rw-r--r--www/js/jquery-ui-1.8.11/themes/base/images/ui-bg_glass_75_dadada_1x400.pngbin0 -> 111 bytes
-rw-r--r--www/js/jquery-ui-1.8.11/themes/base/images/ui-bg_glass_75_e6e6e6_1x400.pngbin0 -> 110 bytes
-rw-r--r--www/js/jquery-ui-1.8.11/themes/base/images/ui-bg_glass_95_fef1ec_1x400.pngbin0 -> 119 bytes
-rw-r--r--www/js/jquery-ui-1.8.11/themes/base/images/ui-bg_highlight-soft_75_cccccc_1x100.pngbin0 -> 101 bytes
-rw-r--r--www/js/jquery-ui-1.8.11/themes/base/images/ui-icons_222222_256x240.pngbin0 -> 4369 bytes
-rw-r--r--www/js/jquery-ui-1.8.11/themes/base/images/ui-icons_2e83ff_256x240.pngbin0 -> 4369 bytes
-rw-r--r--www/js/jquery-ui-1.8.11/themes/base/images/ui-icons_454545_256x240.pngbin0 -> 4369 bytes
-rw-r--r--www/js/jquery-ui-1.8.11/themes/base/images/ui-icons_888888_256x240.pngbin0 -> 4369 bytes
-rw-r--r--www/js/jquery-ui-1.8.11/themes/base/images/ui-icons_cd0a0a_256x240.pngbin0 -> 4369 bytes
-rw-r--r--www/js/jquery-ui-1.8.11/themes/base/jquery.ui.all.css11
-rw-r--r--www/js/jquery-ui-1.8.11/themes/base/jquery.ui.autocomplete.css53
-rw-r--r--www/js/jquery-ui-1.8.11/themes/base/jquery.ui.base.css2
-rw-r--r--www/js/jquery-ui-1.8.11/themes/base/jquery.ui.core.css41
-rw-r--r--www/js/jquery-ui-1.8.11/themes/base/jquery.ui.theme.css252
-rw-r--r--www/js/jstree-1.0-rc2/MultiComboBox.js (renamed from www/js/MultiComboBox.js)0
-rw-r--r--www/js/jstree-1.0-rc2/jquery-1.4.2.js6240
-rw-r--r--www/js/jstree-1.0-rc2/jquery-1.4.2.min.js154
-rw-r--r--www/js/jstree-1.0-rc2/jquery.jstree.js3510
-rw-r--r--www/js/jstree-1.0-rc2/jquery.jstree.min.js1
-rw-r--r--www/js/jstree-1.0-rc2/themes/apple/bg.jpgbin0 -> 331 bytes
-rw-r--r--www/js/jstree-1.0-rc2/themes/apple/d.pngbin0 -> 7765 bytes
-rw-r--r--www/js/jstree-1.0-rc2/themes/apple/dot_for_ie.gifbin0 -> 43 bytes
-rw-r--r--www/js/jstree-1.0-rc2/themes/apple/style.css60
-rw-r--r--www/js/jstree-1.0-rc2/themes/apple/throbber.gifbin0 -> 1849 bytes
-rw-r--r--www/js/jstree-1.0-rc2/themes/classic/d.pngbin0 -> 7535 bytes
-rw-r--r--www/js/jstree-1.0-rc2/themes/classic/dot_for_ie.gifbin0 -> 43 bytes
-rw-r--r--www/js/jstree-1.0-rc2/themes/classic/style.css59
-rw-r--r--www/js/jstree-1.0-rc2/themes/classic/throbber.gifbin0 -> 1849 bytes
-rw-r--r--www/js/jstree-1.0-rc2/themes/default-rtl/d.gifbin0 -> 2872 bytes
-rw-r--r--www/js/jstree-1.0-rc2/themes/default-rtl/d.pngbin0 -> 7459 bytes
-rw-r--r--www/js/jstree-1.0-rc2/themes/default-rtl/dots.gifbin0 -> 132 bytes
-rw-r--r--www/js/jstree-1.0-rc2/themes/default-rtl/style.css83
-rw-r--r--www/js/jstree-1.0-rc2/themes/default-rtl/throbber.gifbin0 -> 1849 bytes
-rw-r--r--www/js/jstree-1.0-rc2/themes/default/d.gifbin0 -> 2944 bytes
-rw-r--r--www/js/jstree-1.0-rc2/themes/default/d.pngbin0 -> 7635 bytes
-rw-r--r--www/js/jstree-1.0-rc2/themes/default/style.css73
-rw-r--r--www/js/jstree-1.0-rc2/themes/default/throbber.gifbin0 -> 1849 bytes
-rw-r--r--www/jsScuttle.php5
-rw-r--r--www/rss.php2
-rw-r--r--www/scuttle.css17
-rw-r--r--www/tag2tagadd.php6
-rw-r--r--www/www-header.php8
147 files changed, 18712 insertions, 2261 deletions
diff --git a/.gitignore b/.gitignore
index 3895c5b..d84d93d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,2 +1,4 @@
dist/
build.properties
+package.xml
+semanticscuttle-dump.sql
diff --git a/build.properties.dist b/build.properties.dist
index b50ad08..887f888 100644
--- a/build.properties.dist
+++ b/build.properties.dist
@@ -1 +1,2 @@
sfuser=FIXME
+websitedir=FIXME
diff --git a/build.xml b/build.xml
index c1db166..9773a63 100644
--- a/build.xml
+++ b/build.xml
@@ -7,14 +7,30 @@
tagging a release, running unit tests etc.
-->
<property file="build.properties" />
+ <property file="html.properties" />
<property name="version-m" value="0.97" />
<property name="version" value="0.97.0" />
- <property name="zipfile" value="${phing.project.name}-${version}.zip" />
- <property name="distfile" value="dist/${zipfile}" />
- <property name="sfproject" value="SemanticScuttle" />
- <property name="sffilepath" value="s/se/semanticscuttle/" />
- <property name="svnpath" value="https://semanticscuttle.svn.sourceforge.net/svnroot/semanticscuttle/" />
+ <property name="stability" value="beta" />
+ <property name="releasenotes" value="- Many SQL optimizations
+- SemanticScuttle shows bookmarks 4 times faster now
+- New config option to skip 'SET NAMES UTF8' call: $dbneedssetnames
+- Do not highlight admin bookmarks when $enableAdminColors is disabled
+- Add russian translation
+- Make HTML export follow the specifications a bit better
+- Fix bug #2953732: faulty error message for duplicate bookmarks
+- Fix bug #2960663: do not send content-type headers twice for ajax/api scripts
+- Fix bug #2976593: fr_FR locale is vietnamese
+" />
+ <property name="zipfile" value="${phing.project.name}-${version}.zip" />
+ <property name="pkgfile" value="${phing.project.name}-${version}.tgz" />
+ <property name="distfile" value="dist/${zipfile}" />
+ <property name="distpkgfile" value="dist/pear/${pkgfile}" />
+ <property name="sfproject" value="SemanticScuttle" />
+ <property name="sffilepath" value="s/se/semanticscuttle/" />
+ <property name="svnpath" value="https://semanticscuttle.svn.sourceforge.net/svnroot/semanticscuttle/" />
+
+ <taskdef classname="phing.tasks.ext.d51PearPkg2Task" name="d51pearpkg2" />
<target name="zip" depends="check"
description="Create zip file for release"
@@ -48,7 +64,151 @@
- <target name="release" depends="check,zip,deploy-sf,svntag"
+ <target name="package" depends="check"
+ description="Creates the pear package"
+ >
+ <!-- fixme: create package.xml with d51pearpkg2 -->
+ <d51pearpkg2 dir="." baseinstalldir="/">
+ <name>SemanticScuttle</name>
+ <summary>A social bookmarking tool</summary>
+ <description>
+ A social bookmarking tool experimenting with new features
+ like structured tags or collaborative descriptions of tags.
+ </description>
+ <channel>semanticscuttle.sourceforge.net</channel>
+
+ <lead user="cweiske" name="Christian Weiske" email="cweiske@cweiske.de" />
+ <license>GPL</license>
+
+ <version release="${version}" api="${version}" />
+ <stability release="${stability}" api="${stability}" />
+
+ <notes>${releasenotes}</notes>
+
+ <dependencies>
+ <php minimum_version="5.2.0" />
+ <pear minimum_version="1.8.1" />
+
+ <package name="HTML_QuickForm2"
+ channel="pear.php.net"
+ minimum_version="0.4.0"
+ />
+
+ </dependencies>
+
+ <!-- map directory (key) to role -->
+ <dirroles key="www">www</dirroles>
+ <dirroles key="data">data</dirroles>
+ <dirroles key="doc">doc</dirroles>
+ <dirroles key="src">php</dirroles>
+ <dirroles key="tests">test</dirroles>
+
+ <!-- do not add the following files to the package.
+ copied from excludes above -->
+ <ignore>**/.gitignore</ignore>
+ <ignore>**/.svn</ignore>
+ <ignore>build*</ignore>
+ <ignore>data/config.php</ignore>
+ <ignore>data/locales/messages.po</ignore>
+ <ignore>data/locales/*/LC_MESSAGES/messages.po</ignore>
+ <ignore>dist/**</ignore>
+ <ignore>doc/developers/**</ignore>
+ <ignore>scripts/**</ignore>
+ <ignore>src/php-gettext/examples/**</ignore>
+ <ignore>src/php-gettext/bin/**</ignore>
+ <ignore>*.tgz</ignore>
+ <ignore>*.properties</ignore>
+
+ <replacement
+ path="src/SemanticScuttle/header.php"
+ type="pear-config"
+ from="@data_dir@" to="data_dir"
+ />
+ <replacement
+ path="www/www-header.php"
+ type="pear-config"
+ from="@data_dir@" to="data_dir"
+ />
+ <replacement
+ path="tests/prepare.php"
+ type="pear-config"
+ from="@data_dir@" to="data_dir"
+ />
+
+ <changelog version="0.97" date="2010-06-09" license="GPL">
+- Many SQL optimizations - SemanticScuttle shows bookmarks 4 times faster now
+- New config option to skip "SET NAMES UTF8" call: $dbneedssetnames
+- Do not highlight admin bookmarks when $enableAdminColors is disabled
+- Add russian translation
+- Make HTML export follow the specifications a bit better
+- Fix bug #2953732: faulty error message for duplicate bookmarks
+- Fix bug #2960663: do not send content-type headers twice for ajax/api scripts
+- Fix bug #2976593: fr_FR locale is vietnamese
+ </changelog>
+
+ <!-- <dirroles key="bin">script</dirroles> -->
+ <!-- <replacement path="bin/doctrine" type="pear-config" from="@php_bin@" to="php_bin" /> -->
+ <!-- <release>
+ <install as="doctrine" name="bin/doctrine" />
+ -->
+ </d51pearpkg2>
+
+ <!-- time to fix the package.xml file since the task does not
+ allow everything we need:
+ - strip the base directory names like src, data and www
+ - remove that dumb baseinstalldir from files
+ - md5sums are generated automatically when packaging
+ -->
+ <!-- yes, we need to generate a 2nd file and move it back -->
+ <copy file="package.xml" tofile="package2.xml" overwrite="true">
+ <filterchain>
+ <replaceregexp>
+ <!-- remove md5sums -->
+ <regexp
+ pattern="md5sum=&quot;[a-z0-9]{32}&quot; "
+ replace=""
+ />
+ <!-- remove baseinstalldir for files -->
+ <regexp
+ pattern="&lt;file baseinstalldir=&quot;/&quot;"
+ replace="&lt;file"
+ />
+ <!-- install-as for different directories -->
+ <regexp
+ pattern="(&lt;file name=&quot;data/(.+?)&quot;)"
+ replace="\1 install-as=&quot;\2&quot;"
+ />
+ <regexp
+ pattern="(&lt;file name=&quot;doc/(.+?)&quot;)"
+ replace="\1 install-as=&quot;\2&quot;"
+ />
+ <regexp
+ pattern="(&lt;file name=&quot;tests/(.+?)&quot;)"
+ replace="\1 install-as=&quot;\2&quot;"
+ />
+ <regexp
+ pattern="(&lt;file name=&quot;www/(.+?)&quot;)"
+ replace="\1 install-as=&quot;SemanticScuttle/\2&quot;"
+ />
+ <regexp
+ pattern="(&lt;file name=&quot;src/(.+?)&quot;)"
+ replace="\1 install-as=&quot;\2&quot;"
+ />
+ </replaceregexp>
+ </filterchain>
+ </copy>
+ <move file="package2.xml" tofile="package.xml" overwrite="true" />
+
+ <!-- package up -->
+ <exec command="pear package" passthru="true" />
+ <move file="${pkgfile}" todir="dist/pear/" />
+
+ <delete file="package.xml" failonerror="true" />
+ </target>
+
+
+
+ <target name="release" depends="check,zip,package,deploy-sf"
description="Release the version on sourceforge"
>
<!-- meta-target -->
@@ -80,12 +240,69 @@
</target>
- <target name="svntag"
- description="create the svn tag for the current version"
+
+ <target name="deploy-sf-pear" depends="check,package"
+ description="Update PEAR channel on sourceforge"
>
+ <available file="${websitedir}"
+ type="dir" property="available.websitedir"
+ />
+ <fail unless="available.websitedir"
+ message="Website directory not set"
+ />
+ <!--
+ 1. rsync channel data from sourceforge to local, deleting
+ superfluous channel files. Need to do that so pirum knows
+ all previous releases when adding the new package
+ 2. update channel with pirum update
+ 3. rsync to sourceforge
+ -->
+ <exec
+ command="rsync --include-from=.rsync-include-files --delete -avP -e ssh ${sfuser},${sfproject}@web.sourceforge.net:htdocs/ ."
+ dir="${websitedir}"
+ escape="false" checkreturn="false"
+ passthru="true"
+ />
+
<exec
- command="svn cp ${svnpath}trunk ${svnpath}/tags/${version} -m 'tag version ${version}'"
- escape="false" checkreturn="true"
+ command="pirum add ${websitedir} ${distpkgfile}"
+ passthru="true"
+ />
+ <!-- fix the generated html -->
+ <!-- yes, we need to generate a 2nd file and move it back -->
+ <copy file="${websitedir}/index.html" tofile="${websitedir}/pirum.html" overwrite="true">
+ <filterchain>
+ <replaceregexp>
+ <!-- make meta links relative -->
+ <regexp
+ pattern="href=&quot;http://semanticscuttle.sourceforge.net/"
+ replace="href=&quot;"
+ />
+ <!-- add sourceforge logo -->
+ <regexp
+ pattern="powered by "
+ replace="powered by ${html.sflogo} and "
+ />
+ </replaceregexp>
+ </filterchain>
+ </copy>
+
+ <!-- overwrite pirum generated index with our own -->
+ <copy file="${websitedir}/our-index.html" tofile="${websitedir}/index.html" overwrite="true" />
+
+ <!-- add our custom css -->
+ <append
+ destFile="${websitedir}/pirum.css"
+ file="${websitedir}/pirum-custom.css"
+ />
+
+ <!-- rsync always returns code 23 on sourceforge releases, so we
+ can't check return values -->
+ <exec
+ command="rsync --include-from=.rsync-include-files -avP -e ssh . ${sfuser},${sfproject}@web.sourceforge.net:htdocs/"
+ dir="${websitedir}"
+ escape="false" checkreturn="false"
+ passthru="true"
/>
</target>
@@ -99,4 +316,4 @@
<fail unless="sffilepath" message="Sourceforge project file path not defined!" />
</target>
-</project> \ No newline at end of file
+</project>
diff --git a/data/config.default.php b/data/config.default.php
index b0a6c50..672431a 100644
--- a/data/config.default.php
+++ b/data/config.default.php
@@ -138,7 +138,7 @@ $dbtype = 'mysql4';
*
* @var string
*/
-$dbhost = 'localhost';
+$dbhost = '127.0.0.1';
/**
* Database port.
@@ -302,7 +302,7 @@ $index_sidebar_blocks = array(
* @var string
* @link http://php.net/date
*/
-$shortdate = 'd-m-Y';
+$shortdate = 'Y-m-d';
/**
* Format of long dates.
@@ -710,4 +710,12 @@ $authEmailSuffix = null;
*/
$unittestUrl = null;
+/**
+ * Allow "unittestMode=1" in URLs.
+ * Should only be enabled on development systems
+ *
+ * @var boolean
+ */
+$allowUnittestMode = false;
+
?>
diff --git a/data/config.php.dist b/data/config.php.dist
index 6439478..c135e8e 100644
--- a/data/config.php.dist
+++ b/data/config.php.dist
@@ -88,7 +88,7 @@ $dbname = 'scuttle';
*
* @var string
*/
-$dbhost = 'localhost';
+$dbhost = '127.0.0.1';
/***************************************************
diff --git a/data/locales/de_DE/LC_MESSAGES/messages.mo b/data/locales/de_DE/LC_MESSAGES/messages.mo
index 0b18fac..05778b7 100644
--- a/data/locales/de_DE/LC_MESSAGES/messages.mo
+++ b/data/locales/de_DE/LC_MESSAGES/messages.mo
Binary files differ
diff --git a/data/locales/de_DE/LC_MESSAGES/messages.po b/data/locales/de_DE/LC_MESSAGES/messages.po
index fdd27a5..a5c774f 100644
--- a/data/locales/de_DE/LC_MESSAGES/messages.po
+++ b/data/locales/de_DE/LC_MESSAGES/messages.po
@@ -604,7 +604,7 @@ msgid ""
"file to your computer"
msgstr ""
"Speichern Sie die resultierende <abbr title=\"Extensible Markup Language"
-"\">XML</abbr-Datei lokal auf Ihrem Computer"
+"\">XML</abbr>-Datei lokal auf Ihrem Computer"
#: data/templates/importDelicious.tpl.php:35
msgid ""
diff --git a/data/locales/fr_CA/LC_MESSAGES/messages.po b/data/locales/fr_CA/LC_MESSAGES/messages.po
index 4bdb4b9..ae74c4b 100644
--- a/data/locales/fr_CA/LC_MESSAGES/messages.po
+++ b/data/locales/fr_CA/LC_MESSAGES/messages.po
@@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: Scuttle\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2008-04-24 19:03+0200\n"
+"POT-Creation-Date: 2010-09-15 19:15+0200\n"
"PO-Revision-Date: 2008-04-24 19:07+0100\n"
"Last-Translator: BenjaminHKB <benjamin.huynh-kim-bang@loria.fr>\n"
"Language-Team: fr-FR <toony.sf@chezouam.net>\n"
@@ -19,1151 +19,1528 @@ msgstr ""
"X-Poedit-Country: FRANCE\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
-#: ../../../about.php:25
-#: ../../../templates/toolbar.inc.php:16
-#: ../../../templates/toolbar.inc.php:25
-msgid "About"
-msgstr "À propos"
-
-#: ../../../ajaxDelete.php:30
-msgid "You are not allowed to delete this bookmark"
-msgstr "Vous n'êtes pas autorisés à supprimer ce signet"
-
-#: ../../../ajaxDelete.php:34
-#: ../../../edit.php:78
-msgid "Failed to delete bookmark"
-msgstr "Erreur dans la suppression du signet"
-
-#: ../../../alltags.php:48
-msgid "All Tags"
-msgstr "Tous les mots-cl&eacute;s"
-
-#: ../../../alltags.php:57
-#: ../../../bookmarks.php:72
-#: ../../../populartags.php:58
-#: ../../../profile.php:44
-#: ../../../rss.php:62
-#: ../../../search.php:88
-#: ../../../watch.php:34
-#: ../../../watchlist.php:61
-#, php-format
-msgid "User with username %s was not found"
-msgstr "L'utilisateur %s n'a pas été trouvé."
-
-#: ../../../bookmarkcommondescriptionedit.php:35
-#: ../../../tag2tagadd.php:31
-#: ../../../tag2tagdelete.php:31
-#: ../../../tag2tagedit.php:31
-#: ../../../tagcommondescriptionedit.php:35
-#: ../../../tagedit.php:34
-msgid "Permission denied."
-msgstr "Permission non accordée."
-
-#: ../../../bookmarkcommondescriptionedit.php:45
-msgid "Bookmark common description updated"
-msgstr "Description commune du signet mise à jour."
-
-#: ../../../bookmarkcommondescriptionedit.php:48
-msgid "Failed to update the bookmark common description"
-msgstr "Erreur dans la mise à jour de la description du signet"
-
-#: ../../../bookmarkcommondescriptionedit.php:57
-msgid "Edit Bookmark Common Description"
-msgstr "Editer la description commune du signet"
-
-#: ../../../bookmarks.php:95
-#: ../../../edit.php:44
-msgid "Your bookmark must have a title and an address"
-msgstr "Votre signet doit avoir un titre et une adresse."
-
-#: ../../../bookmarks.php:115
-#: ../../../edit.php:58
-msgid "Bookmark saved"
-msgstr "Signet enregistré."
-
-#: ../../../bookmarks.php:123
-#: ../../../import.php:99
-#: ../../../importNetscape.php:74
-msgid "There was an error saving your bookmark. Please try again or contact the administrator."
-msgstr "Il y a eu une erreur en enregistrant ce signet. Veuillez rééssayer ou contacter votre administrateur."
-
-#: ../../../bookmarks.php:161
-#: ../../../templates/toolbar.inc.php:14
-msgid "Add a Bookmark"
-msgstr "Ajouter un signet"
-
-#: ../../../bookmarks.php:164
-msgid "Add Bookmark"
-msgstr "Ajouter signet"
-
-#: ../../../bookmarks.php:167
-msgid "You must be logged in before you can add bookmarks."
-msgstr "Vous devez être authentifié avant de pouvoir ajouter des signets."
-
-#: ../../../bookmarks.php:218
-msgid "My Bookmarks"
-msgstr "Mes signets"
-
-#: ../../../edit.php:29
-msgid "Edit Bookmark"
-msgstr "Editer le signet"
-
-#: ../../../edit.php:34
-#, php-format
-msgid "Bookmark with id %s not was not found"
-msgstr "Signet %s non trouvé"
-
-#: ../../../edit.php:39
-msgid "You are not allowed to edit this bookmark"
-msgstr "Vous n'êtes pas autorisé à éditer ce signet."
-
-#: ../../../edit.php:55
-msgid "Error while saving your bookmark"
-msgstr "Erreur pendant l'enregistrement de votre signet."
-
-#: ../../../edit.php:88
-#: ../../../templates/editprofile.tpl.php:51
-msgid "Save Changes"
-msgstr "Enregistrer les modifications"
-
-#: ../../../functions.inc.php:108
+#: src/SemanticScuttle/functions.php:189
msgid "message_die() was called multiple times."
msgstr "message_die() was called multiple times. ?"
-#: ../../../functions.inc.php:120
+#: src/SemanticScuttle/functions.php:201
msgid "SQL Error"
msgstr "Erreur SQL"
-#: ../../../functions.inc.php:126
+#: src/SemanticScuttle/functions.php:207
msgid "Line"
msgstr "Ligne"
-#: ../../../functions.inc.php:126
-#: ../../../templates/importDelicious.tpl.php:8
-#: ../../../templates/importNetscape.tpl.php:9
+#: src/SemanticScuttle/functions.php:207
+#: data/templates/importDelicious.tpl.php:8
+#: data/templates/importNetscape.tpl.php:9
+#: data/templates/importStructure.tpl.php:10
msgid "File"
msgstr "Fichier"
-#: ../../../functions.inc.php:132
+#: src/SemanticScuttle/functions.php:215
msgid "Information"
msgstr "Information"
-#: ../../../functions.inc.php:137
+#: src/SemanticScuttle/functions.php:220
msgid "Critical Information"
msgstr "Information critique."
-#: ../../../functions.inc.php:142
+#: src/SemanticScuttle/functions.php:225
msgid "An error occured"
msgstr "Une erreur s'est produite."
-#: ../../../functions.inc.php:145
+#: src/SemanticScuttle/functions.php:228
msgid "General Error"
msgstr "Erreur générale."
-#: ../../../functions.inc.php:153
+#: src/SemanticScuttle/functions.php:236
msgid "An critical error occured"
msgstr "Une erreur critique s'est produite."
-#: ../../../functions.inc.php:156
+#: src/SemanticScuttle/functions.php:239
msgid "Critical Error"
msgstr "Erreur critique."
-#: ../../../functions.inc.php:165
+#: src/SemanticScuttle/functions.php:248
msgid "DEBUG MODE"
msgstr "Mode de débogage."
-#: ../../../history.php:65
-msgid "History"
-msgstr "Historique"
+#: data/templates/about.tpl.php:6
+msgid ""
+"<strong>Store</strong> all your favourite links in one place, accessible "
+"from anywhere."
+msgstr ""
+"<strong>Conservez</strong> tous vos signets au même endroit, accessibles de "
+"partout. "
-#: ../../../history.php:66
-#, php-format
-msgid "History for %s"
-msgstr "Historique de %s"
+#: data/templates/about.tpl.php:7
+msgid ""
+"<strong>Share</strong> your bookmarks with everyone, with friends on your "
+"watchlist or just keep them private."
+msgstr ""
+"<strong>Partagez</strong> vos signets avec tout le monde, avec les "
+"utilisateurs autorisés ou gardez-les pour vous."
-#: ../../../history.php:82
-msgid "Address was not found"
-msgstr "L'adresse n'a pas été trouvée."
+#: data/templates/about.tpl.php:8
+msgid ""
+"<strong>Tag</strong> your bookmarks with as many labels as you want, instead "
+"of wrestling with folders."
+msgstr ""
+"<strong>Taggez</strong> vos signets avec autant de labels que vous le "
+"souhaitez au lieu de les hiérarchiser avec des dossiers."
-#: ../../../import.php:41
-msgid "Could not open XML input"
-msgstr "Impossible d'ouvrir le flux XML."
+#: data/templates/about.tpl.php:9
+msgid "Register now"
+msgstr "S'enregistrer maintenant"
-#: ../../../import.php:45
+#: data/templates/about.tpl.php:9
#, php-format
-msgid "XML error: %s at line %d"
-msgstr "Erreur XML: %s à la ligne %d"
-
-#: ../../../import.php:54
-msgid "Import Bookmarks from del.icio.us"
-msgstr "Importer les signet depuis del.icio.us"
-
-#: ../../../import.php:86
-#: ../../../importNetscape.php:64
-msgid "You have already submitted this bookmark."
-msgstr "Vous avez déjà enregistré ce signet."
+msgid " to start using %s!"
+msgstr "pour commencer à employer %s !"
-#: ../../../import.php:97
-#: ../../../importNetscape.php:72
-msgid "Bookmark imported."
-msgstr "Signet importé."
+#: data/templates/about.tpl.php:12
+msgid "Geek Stuff"
+msgstr "Pour les Geeks"
-#: ../../../importNetscape.php:81
-msgid "Import Bookmarks from Browser File"
-msgstr "Importer les signets depuis un fichier"
+#: data/templates/about.tpl.php:14
+msgid "is licensed under the "
+msgstr "est sous licence"
-#: ../../../index.php:32
-msgid "You have now logged out"
-msgstr "Vous êtes maintenant déconnecté."
+#: data/templates/about.tpl.php:14
+msgid "you can freely host it on your own web server."
+msgstr "vous pouvez librement l'installer sur votre serveur Web"
-#: ../../../index.php:39
+#: data/templates/about.tpl.php:15
#, php-format
-msgid "%s: Recent bookmarks"
-msgstr "%s: Signets récents"
-
-#: ../../../index.php:73
-msgid "Store, share and tag your favourite links"
-msgstr "Conservez, partagez et libellez vos liens favoris"
-
-#: ../../../index.php:74
-msgid "All Bookmarks"
-msgstr "Tous les signets"
-
-#: ../../../jsScuttle.php:22
-#: ../../../templates/tag2tagadd.tpl.php:21
-#: ../../../templates/tag2tagdelete.tpl.php:13
-#: ../../../templates/tag2tagedit.tpl.php:14
-#: ../../../templates/tag2tagedit.tpl.php:35
-#: ../../../templates/tagdelete.tpl.php:6
-msgid "Are you sure?"
-msgstr "Etes-vous sûr ?"
-
-#: ../../../jsScuttle.php:22
-#: ../../../templates/tag2tagdelete.tpl.php:15
-#: ../../../templates/tag2tagedit.tpl.php:16
-#: ../../../templates/tagdelete.tpl.php:8
-msgid "Yes"
-msgstr "Oui"
-
-#: ../../../jsScuttle.php:22
-#: ../../../templates/tag2tagdelete.tpl.php:16
-#: ../../../templates/tag2tagedit.tpl.php:17
-#: ../../../templates/tagdelete.tpl.php:9
-msgid "No"
-msgstr "Non"
-
-#: ../../../jsScuttle.php:68
-msgid "Available"
-msgstr "Disponible"
-
-#: ../../../jsScuttle.php:71
-msgid "Not Available"
-msgstr "Non Disponible"
-
-#: ../../../login.php:38
-msgid "The details you have entered are incorrect. Please try again."
-msgstr "Les informations que vous avez entrées sont incorrectes. Veuillez recommencer."
+msgid ""
+"%1$s supports most of the <a href=\"http://del.icio.us/doc/api\">del.icio.us "
+"<abbr title=\"Application Programming Interface\">API</abbr></a>. Almost all "
+"of the neat tools made for that system can be modified to work with %1$s "
+"instead. If you find a tool that won't let you change the API address, ask "
+"the creator to add this setting. You never know, they might just do it."
+msgstr ""
+"%1$s supporte la plupart de l'<a href=\"http://del.icio.us/doc/api\"><abbr "
+"title=\"Application Programming Interface\">API</abbr> del.icio.us</a>."
-#: ../../../login.php:48
-#: ../../../templates/login.tpl.php:26
-#: ../../../templates/toolbar.inc.php:26
-msgid "Log In"
-msgstr "Se connecter"
+#: data/templates/about.tpl.php:24
+msgid "Tips"
+msgstr ""
-#: ../../../password.php:31
-msgid "You must enter your username."
-msgstr "Vous devez entrer votre nom d'utilisateur."
+#: data/templates/about.tpl.php:26
+msgid "Add search plugin into your browser:"
+msgstr ""
-#: ../../../password.php:35
-msgid "You must enter your <abbr title=\"electronic mail\">e-mail</abbr> address."
-msgstr "Vous <em>devez</em> saisir une <abbr title=\"adresse électronique\">E-mail</abbr>."
+#: data/templates/about.tpl.php:27
+msgid ""
+"The secret tag \"system:unfiled\" allows you to find bookmarks without tags."
+msgstr ""
-#: ../../../password.php:42
-msgid "No matches found for that username."
-msgstr "Rien de trouvé pour ce nom d'utilisateur."
+#: data/templates/about.tpl.php:28
+msgid ""
+"The secret tag \"system:imported\" allows you to find imported bookmarks."
+msgstr ""
-#: ../../../password.php:45
+#: data/templates/admin.tpl.php:5
#, fuzzy
-msgid "No matches found for that combination of username and <abbr title=\"electronic mail\">e-mail</abbr> address."
-msgstr "Nous n'avons rien trouvé pour cette combinaison de nom d'utilisateur et d'<abbr title=\"adresse mail\">e-mail</abbr>."
-
-#: ../../../password.php:53
-msgid "There was an error while generating your new password. Please try again."
-msgstr "Il y a eu une erreur en enregistrant ce signet. Veuillez rééssayer ou contacter votre administrateur."
-
-#: ../../../password.php:57
-msgid "Your new password is:"
-msgstr "Votre nouveau mot de passe est:"
-
-#: ../../../password.php:57
-msgid "To keep your bookmarks secure, you should change this password in your profile the next time you log in."
-msgstr "Pour garder vos signets sûrs, vous devriez changer ce mot de passe dans votre profil lors de votre prochaine authentification."
-
-#: ../../../password.php:60
-#, php-format
-msgid "%s Account Information"
-msgstr "Informations du compte de %s"
-
-#: ../../../password.php:62
-#, php-format
-msgid "New password generated and sent to %s"
-msgstr "Nouveau mot de passe généré et envoyé à l'adresse %s"
-
-#: ../../../password.php:69
-msgid "Forgotten Password"
-msgstr "Mot de passe oublié"
-
-#: ../../../populartags.php:49
-#: ../../../templates/dynamictags.inc.php:101
-#: ../../../templates/sidebar.block.common.php:9
-#: ../../../templates/sidebar.block.menu.php:68
-#: ../../../templates/sidebar.block.popular.php:15
-#: ../../../templates/sidebar.block.recent.php:30
-#: ../../../templates/toolbar.inc.php:24
-msgid "Popular Tags"
-msgstr "Mots-cl&eacute;s populaires"
-
-#: ../../../profile.php:52
-#: ../../../watchlist.php:116
-msgid "Username was not specified"
-msgstr "Le nom d'utilisateur n'a pas été spécifié."
-
-#: ../../../profile.php:58
-msgid "My Profile"
-msgstr "Mon Profil"
-
-#: ../../../profile.php:60
-#: ../../../templates/toolbar.inc.php:13
-msgid "Profile"
-msgstr "Profil"
-
-#: ../../../profile.php:78
-msgid "Password and confirmation do not match."
-msgstr "Le mot de passe et sa vérification ne correspondent pas."
-
-#: ../../../profile.php:82
-msgid "Password must be at least 6 characters long."
-msgstr "Le mot de passe doit avoir au moins 6 caractères."
-
-#: ../../../profile.php:86
-msgid "E-mail address is not valid."
-msgstr "Adresse de courrier électronique invalide."
-
-#: ../../../profile.php:90
-msgid "An error occurred while saving your changes."
-msgstr "Une erreur s'est produite pendant l'enregistrement de vos modifications."
-
-#: ../../../profile.php:92
-msgid "Changes saved."
-msgstr "Modifications enregistrées."
-
-#: ../../../register.php:33
-msgid "You <em>must</em> enter a username, password and e-mail address."
-msgstr "Vous <em>devez</em> saisir un nom d'utilisateur, un mot de passe, un nom et un <abbr title=\"adresse électronique\">e-mail</abbr>"
-
-#: ../../../register.php:37
-msgid "This username has been reserved, please make another choice."
-msgstr "Ce nom d'utilisateur existe déjà, veuillez en choisir un autre."
-
-#: ../../../register.php:41
-msgid "This username already exists, please make another choice."
-msgstr "Ce nom d'utilisateur existe déjà, veuillez en choisir un autre."
-
-#: ../../../register.php:45
-msgid "E-mail address is not valid. Please try again."
-msgstr "Adresse de courrier électronique invalide. Veuilez réessayer."
-
-#: ../../../register.php:49
-msgid "Antispam answer is not valid. Please try again."
-msgstr "La réponse antispam n'est pas valide. Veuillez réessayer."
-
-#: ../../../register.php:58
-msgid "You have successfully registered. Enjoy!"
-msgstr "Votre inscription a bien été prise en compte !"
-
-#: ../../../register.php:60
-msgid "Registration failed. Please try again."
-msgstr "Enregistrement raté. Veuillez rééssayer."
-
-#: ../../../register.php:66
-#: ../../../templates/register.tpl.php:41
-#: ../../../templates/toolbar.inc.php:27
-msgid "Register"
-msgstr "S'enregistrer"
-
-#: ../../../rss.php:79
-#, php-format
-msgid "Recent bookmarks posted to %s"
-msgstr "Signets ajoutés récemment à %s"
-
-#: ../../../search.inc.php:13
-#: ../../../search.inc.php:41
-msgid "Search"
-msgstr "Chercher dans"
-
-#: ../../../search.inc.php:19
-msgid "this user's bookmarks"
-msgstr "les signets de cet utilisateur"
-
-#: ../../../search.inc.php:24
-msgid "my bookmarks"
-msgstr "mes signets"
-
-#: ../../../search.inc.php:25
-msgid "my watchlist"
-msgstr "ma liste des consultés"
-
-#: ../../../search.inc.php:29
-msgid "all bookmarks"
-msgstr "tous les signets"
-
-#: ../../../search.inc.php:32
-msgid "for"
-msgstr "pour"
-
-#: ../../../search.php:59
-#: ../../../search.php:108
-msgid "Search Bookmarks"
-msgstr "Recherche de signets"
-
-#: ../../../search.php:65
-msgid "Search Results"
-msgstr "Résultats de recherche"
-
-#: ../../../tag2tagadd.php:44
-msgid "Tag link created"
-msgstr "Lien entre mot-cl&eacute; créé."
-
-#: ../../../tag2tagadd.php:47
-msgid "Failed to create the link"
-msgstr "Impossible de créer le lien"
-
-#: ../../../tag2tagadd.php:58
-msgid "Add Tag Link"
-msgstr "Ajout d'un lien entre mots-cl&eacute;s"
-
-#: ../../../tag2tagdelete.php:43
-#: ../../../tag2tagedit.php:43
-msgid "Tag link deleted"
-msgstr "Effacement d'un lien entre mots-cl&eacute;s"
-
-#: ../../../tag2tagdelete.php:46
-#: ../../../tag2tagedit.php:46
-msgid "Failed to delete the link"
-msgstr "Impossible d'effacer le lien"
-
-#: ../../../tag2tagdelete.php:58
-msgid "Delete Link Between Tags"
-msgstr "Effacer un lien entre mots-cl&eacute;s"
-
-#: ../../../tag2tagedit.php:58
-msgid "Edit Link Between Tags"
-msgstr "Editer un lien entre mots-cl&eacute;s"
-
-#: ../../../tagcommondescriptionedit.php:45
-msgid "Tag common description updated"
-msgstr "Editer la description commune du mot-cl&eacute;"
-
-#: ../../../tagcommondescriptionedit.php:48
-msgid "Failed to update the tag common description"
-msgstr "Impossible de mettre à jour la description commune du mot-cl&eacute;"
-
-#: ../../../tagcommondescriptionedit.php:55
-#: ../../../templates/sidebar.block.tagactions.php:27
-msgid "Edit Tag Common Description"
-msgstr "Editer la description commune du mot-cl&eacute;"
-
-#: ../../../tagdelete.php:33
-msgid "Tag deleted"
-msgstr "Mot-cl&eacute; effacé"
-
-#: ../../../tagdelete.php:36
-msgid "Failed to delete the tag"
-msgstr "Impossible d'effacer le mot-cl&eacute;"
-
-#: ../../../tagdelete.php:44
-#: ../../../templates/sidebar.block.tagactions.php:23
-msgid "Delete Tag"
-msgstr "Supprimer le mot-cl&eacute;"
-
-#: ../../../tagedit.php:44
-msgid "Tag description updated"
-msgstr "Description du mot-cl&eacute; mise à jour"
-
-#: ../../../tagedit.php:47
-msgid "Failed to update the tag description"
-msgstr "Impossible de mettre à jour la description du mot-cl&eacute;"
-
-#: ../../../tagedit.php:54
-#: ../../../templates/sidebar.block.tagactions.php:25
-msgid "Edit Tag Description"
-msgstr "Editer la description du mot-cl&eacute;"
-
-#: ../../../tagrename.php:50
-msgid "Tag renamed"
-msgstr "Mot-cl&eacute; renommé"
-
-#: ../../../tagrename.php:54
-msgid "Failed to rename the tag"
-msgstr "Erreur dans le renommage du mot-cl&eacute;"
-
-#: ../../../tagrename.php:61
-#: ../../../templates/sidebar.block.tagactions.php:10
-msgid "Rename Tag"
-msgid_plural "Rename Tags"
-msgstr[0] "Renommer le mot-cl&eacute;"
-msgstr[1] "Renommer les mots-cl&eacute;s"
-
-#: ../../../tags.php:38
-#: ../../../templates/editbookmark.tpl.php:44
-#: ../../../templates/toolbar.inc.php:11
-msgid "Tags"
-msgstr "Mots-clés"
+msgid "Users management"
+msgstr "Nom d'utilisateur"
-#: ../../../users.php:33
-msgid "Users"
-msgstr "Utilisateurs"
+#: data/templates/admin.tpl.php:14
+msgid "Public/Shared/Private"
+msgstr ""
-#: ../../../watch.php:46
-msgid "User removed from your watchlist"
-msgstr "Utilisateur enlevé de votre liste des consultés"
+#: data/templates/admin.tpl.php:14 data/templates/bookmarks.tpl.php:93
+msgid "bookmark(s)"
+msgstr "signet(s)"
-#: ../../../watch.php:48
-msgid "User added to your watchlist"
-msgstr "Utilisateur ajouté à la liste des consultés."
+#: data/templates/admin.tpl.php:19 data/templates/tag2tagadd.tpl.php:21
+#: data/templates/tag2tagdelete.tpl.php:13
+#: data/templates/tag2tagedit.tpl.php:14 data/templates/tag2tagedit.tpl.php:35
+#: data/templates/tagdelete.tpl.php:6 www/jsScuttle.php:23
+msgid "Are you sure?"
+msgstr "Etes-vous sûr ?"
-#: ../../../watchlist.php:103
-#, fuzzy
-msgid "My Watchlist"
-msgstr "Liste des signets vus"
+#: data/templates/admin.tpl.php:19 data/templates/bookmarks.tpl.php:267
+msgid "Delete"
+msgstr "Supprimer"
-#: ../../../watchlist.php:105
-#: ../../../templates/toolbar.inc.php:12
+#: data/templates/admin.tpl.php:27
#, fuzzy
-msgid "Watchlist"
-msgstr "Liste des signets vus"
-
-#: ../../../templates/about.tpl.php:6
-msgid "<strong>Store</strong> all your favourite links in one place, accessible from anywhere."
-msgstr "<strong>Conservez</strong> tous vos signets au même endroit, accessibles de partout. "
-
-#: ../../../templates/about.tpl.php:7
-msgid "<strong>Share</strong> your bookmarks with everyone, with friends on your watchlist or just keep them private."
-msgstr "<strong>Partagez</strong> vos signets avec tout le monde, avec les utilisateurs autorisés ou gardez-les pour vous."
-
-#: ../../../templates/about.tpl.php:8
-msgid "<strong>Tag</strong> your bookmarks with as many labels as you want, instead of wrestling with folders."
-msgstr "<strong>Taggez</strong> vos signets avec autant de labels que vous le souhaitez au lieu de les hiérarchiser avec des dossiers."
-
-#: ../../../templates/about.tpl.php:9
-msgid "Register now"
-msgstr "S'enregistrer maintenant"
-
-#: ../../../templates/about.tpl.php:9
-#, php-format
-msgid " to start using %s!"
-msgstr "pour commencer à employer %s !"
-
-#: ../../../templates/about.tpl.php:12
-msgid "Geek Stuff"
-msgstr "Pour les Geeks"
-
-#: ../../../templates/about.tpl.php:14
-msgid "is licensed under the "
-msgstr "est sous licence"
+msgid "Other actions"
+msgstr "Instructions"
-#: ../../../templates/about.tpl.php:14
-msgid "you can freely host it on your own web server."
-msgstr "vous pouvez librement l'installer sur votre serveur Web"
+#: data/templates/admin.tpl.php:29
+msgid "Check all URLs (May take some time)"
+msgstr ""
-#: ../../../templates/about.tpl.php:15
-#, php-format
-msgid "%1$s supports most of the <a href=\"http://del.icio.us/doc/api\">del.icio.us <abbr title=\"Application Programming Interface\">API</abbr></a>. Almost all of the neat tools made for that system can be modified to work with %1$s instead. If you find a tool that won't let you change the API address, ask the creator to add this setting. You never know, they might just do it."
-msgstr "%1$s supporte la plupart de l'<a href=\"http://del.icio.us/doc/api\"><abbr title=\"Application Programming Interface\">API</abbr> del.icio.us</a>."
+#: data/templates/bookmarkcommondescriptionedit.tpl.php:16
+msgid ""
+"Collaborative description: these fields can be viewed and modified by every "
+"users"
+msgstr ""
-#: ../../../templates/bookmarkcommondescriptionedit.tpl.php:15
-#: ../../../templates/bookmarks.tpl.php:67
-#: ../../../templates/editbookmark.tpl.php:34
+#: data/templates/bookmarkcommondescriptionedit.tpl.php:18
+#: data/templates/bookmarks.tpl.php:137 data/templates/editbookmark.tpl.php:43
msgid "Title"
msgstr "Titre"
-#: ../../../templates/bookmarkcommondescriptionedit.tpl.php:20
-#: ../../../templates/editbookmark.tpl.php:39
-#: ../../../templates/editprofile.tpl.php:46
-#: ../../../templates/profile.tpl.php:28
-#: ../../../templates/tagcommondescriptionedit.tpl.php:13
-#: ../../../templates/tagedit.tpl.php:13
+#: data/templates/bookmarkcommondescriptionedit.tpl.php:23
+#: data/templates/editbookmark.tpl.php:49
+#: data/templates/editprofile.tpl.php:47 data/templates/profile.tpl.php:33
+#: data/templates/tagcommondescriptionedit.tpl.php:13
+#: data/templates/tagedit.tpl.php:12
msgid "Description"
msgstr "Description"
-#: ../../../templates/bookmarkcommondescriptionedit.tpl.php:28
-#: ../../../templates/tagcommondescriptionedit.tpl.php:21
+#: data/templates/bookmarkcommondescriptionedit.tpl.php:31
+#: data/templates/tagcommondescriptionedit.tpl.php:21
msgid "Last modification:"
msgstr "Dernière modification :"
-#: ../../../templates/bookmarkcommondescriptionedit.tpl.php:39
-#: ../../../templates/tagcommondescriptionedit.tpl.php:32
-#: ../../../templates/tagedit.tpl.php:19
+#: data/templates/bookmarkcommondescriptionedit.tpl.php:42
+#: data/templates/tagcommondescriptionedit.tpl.php:32
+#: data/templates/tagedit.tpl.php:18
msgid "Update"
msgstr "Mettre à jour"
-#: ../../../templates/bookmarkcommondescriptionedit.tpl.php:40
-#: ../../../templates/tag2tagadd.tpl.php:24
-#: ../../../templates/tag2tagedit.tpl.php:38
-#: ../../../templates/tagcommondescriptionedit.tpl.php:33
-#: ../../../templates/tagedit.tpl.php:20
-#: ../../../templates/tagrename.tpl.php:25
+#: data/templates/bookmarkcommondescriptionedit.tpl.php:43
+#: data/templates/editbookmark.tpl.php:103
+#: data/templates/tag2tagadd.tpl.php:24 data/templates/tag2tagedit.tpl.php:38
+#: data/templates/tagcommondescriptionedit.tpl.php:33
+#: data/templates/tagedit.tpl.php:19 data/templates/tagrename.tpl.php:25
msgid "Cancel"
msgstr "Annuler"
-#: ../../../templates/bookmarks.tpl.php:34
-#: ../../../templates/bookmarks.tpl.php:37
-msgid "edit common description"
+#: data/templates/bookmarks-vote-horizontal.inc.tpl.php:24
+#, php-format
+msgid "Voting <span class=\"voting\">%d</span>"
+msgstr ""
+
+#: data/templates/bookmarks-vote-horizontal.inc.tpl.php:32
+#: data/templates/bookmarks-vote-horizontal.inc.tpl.php:35
+msgid "Vote for"
+msgstr ""
+
+#: data/templates/bookmarks-vote-horizontal.inc.tpl.php:43
+#: data/templates/bookmarks-vote-horizontal.inc.tpl.php:46
+msgid "Vote against"
+msgstr ""
+
+#: data/templates/bookmarks.tpl.php:26
+msgid "Bookmarks on this page are managed by an admin user."
+msgstr ""
+
+#: data/templates/bookmarks.tpl.php:51 data/templates/bookmarks.tpl.php:52
+#, fuzzy
+msgid "Edit the common description of this tag"
+msgstr "Modifier la description public de ce mot-cl&eacute;"
+
+#: data/templates/bookmarks.tpl.php:55 data/templates/bookmarks.tpl.php:56
+#, fuzzy
+msgid "Edit the common description of this bookmark"
msgstr "éditer la description commune"
-#: ../../../templates/bookmarks.tpl.php:64
-msgid "bookmark(s)"
-msgstr "signet(s)"
+#: data/templates/bookmarks.tpl.php:76 data/templates/bookmarks.tpl.php:77
+msgid "Edit your personal description of this tag"
+msgstr "Modifier la description priv&eacute;e de ce mot-cl&eacute;"
-#: ../../../templates/bookmarks.tpl.php:65
-#: ../../../templates/tags.tpl.php:10
-#: ../../../templates/users.tpl.php:8
+#: data/templates/bookmarks.tpl.php:93 data/templates/tags.tpl.php:10
+#: data/templates/users.tpl.php:8
msgid "Sort by:"
msgstr "Classer par :"
-#: ../../../templates/bookmarks.tpl.php:66
+#: data/templates/bookmarks.tpl.php:135
msgid "Date"
msgstr "Date"
-#: ../../../templates/bookmarks.tpl.php:71
-msgid "URL"
-msgstr "URL"
+#: data/templates/bookmarks.tpl.php:140
+msgid "Voting"
+msgstr ""
-#: ../../../templates/bookmarks.tpl.php:81
+#: data/templates/bookmarks.tpl.php:149
msgid "Bookmarks from other users for this tag"
msgstr "Signets des autres utilisateurs pour ce mot-cl&eacute;"
-#: ../../../templates/bookmarks.tpl.php:86
+#: data/templates/bookmarks.tpl.php:154
msgid "Only your bookmarks for this tag"
msgstr "Uniquement vos signets pour ce mot-cl&eacute;"
-#: ../../../templates/bookmarks.tpl.php:129
+#: data/templates/bookmarks.tpl.php:177 data/templates/bookmarks.tpl.php:183
+msgid "First"
+msgstr "Première"
+
+#: data/templates/bookmarks.tpl.php:178 data/templates/bookmarks.tpl.php:184
+msgid "Previous"
+msgstr "Précédent"
+
+#: data/templates/bookmarks.tpl.php:191 data/templates/bookmarks.tpl.php:194
+msgid "Next"
+msgstr "Suivant"
+
+#: data/templates/bookmarks.tpl.php:192 data/templates/bookmarks.tpl.php:195
+msgid "Last"
+msgstr "Dernière"
+
+#: data/templates/bookmarks.tpl.php:205
+#, php-format
+msgid "Page %d of %d"
+msgstr "Page %d de %d"
+
+#: data/templates/bookmarks.tpl.php:261
+#, fuzzy
+msgid "Tags:"
+msgstr "Mots-clés"
+
+#: data/templates/bookmarks.tpl.php:267
msgid "Edit"
msgstr "Editer"
-#: ../../../templates/bookmarks.tpl.php:129
-msgid "Delete"
-msgstr "Supprimer"
+#: data/templates/bookmarks.tpl.php:271
+msgid "Last update"
+msgstr ""
-#: ../../../templates/bookmarks.tpl.php:135
+#: data/templates/bookmarks.tpl.php:274
msgid "by"
msgstr "par"
-#: ../../../templates/bookmarks.tpl.php:139
-msgid "to"
-msgstr "dans"
+#: data/templates/bookmarks.tpl.php:276
+msgid "you"
+msgstr "vous"
-#: ../../../templates/bookmarks.tpl.php:147
+#: data/templates/bookmarks.tpl.php:290
#, fuzzy, php-format
msgid " and %s1 other%s"
msgstr " et les autres %s"
-#: ../../../templates/bookmarks.tpl.php:150
+#: data/templates/bookmarks.tpl.php:293
#, fuzzy, php-format
msgid " and %2$s%1$s others%3$s"
msgstr " et les autres %s"
-#: ../../../templates/bookmarks.tpl.php:159
+#: data/templates/bookmarks.tpl.php:304
+#, fuzzy
+msgid "Copy this bookmark to YOUR bookmarks."
+msgstr "Importer les signets depuis un fichier"
+
+#: data/templates/bookmarks.tpl.php:305
msgid "Copy"
msgstr "Copier"
-#: ../../../templates/bookmarks.tpl.php:218
-#: ../../../templates/bookmarks.tpl.php:224
-msgid "First"
-msgstr "Première"
-
-#: ../../../templates/bookmarks.tpl.php:219
-#: ../../../templates/bookmarks.tpl.php:225
-msgid "Previous"
-msgstr "Précédent"
+#: data/templates/bookmarks.tpl.php:325
+msgid "This bookmark is certified by an admin user."
+msgstr ""
-#: ../../../templates/bookmarks.tpl.php:232
-#: ../../../templates/bookmarks.tpl.php:235
-msgid "Next"
-msgstr "Suivant"
+#: data/templates/bookmarks.tpl.php:371
+#, fuzzy
+msgid "Private Note on this bookmark"
+msgstr "Vous n'êtes pas autorisé à éditer ce signet."
-#: ../../../templates/bookmarks.tpl.php:233
-#: ../../../templates/bookmarks.tpl.php:236
-msgid "Last"
-msgstr "Dernière"
+#: data/templates/bookmarks.tpl.php:383
+msgid "Come back to the top of this page."
+msgstr ""
-#: ../../../templates/bookmarks.tpl.php:246
-#, php-format
-msgid "Page %d of %d"
-msgstr "Page %d de %d"
+#: data/templates/bookmarks.tpl.php:383
+msgid "Top of the page"
+msgstr ""
-#: ../../../templates/bookmarks.tpl.php:252
+#: data/templates/bookmarks.tpl.php:389
msgid "No bookmarks available"
msgstr "Pas de signets disponibles."
-#: ../../../templates/dynamictags.inc.php:108
-#: ../../../templates/sidebar.block.common.php:20
-#: ../../../templates/sidebar.block.popular.php:26
-#: ../../../templates/sidebar.block.recent.php:25
-#: ../../../templates/tags.tpl.php:19
+#: data/templates/bottom.inc.php:5 data/templates/toolbar.inc.php:15
+#: data/templates/toolbar.inc.php:28 www/about.php:23 www/about.php:24
+msgid "About"
+msgstr "À propos"
+
+#: data/templates/bottom.inc.php:7
+msgid "Propulsed by "
+msgstr ""
+
+#: data/templates/dynamictags.inc.php:47
+#: data/templates/sidebar.block.common.php:19
+#: data/templates/sidebar.block.popular.php:34
+#: data/templates/sidebar.block.recent.php:29 data/templates/tags.tpl.php:19
msgid "bookmark"
msgid_plural "bookmarks"
msgstr[0] "signet"
msgstr[1] "Signets"
-#: ../../../templates/editbookmark.tpl.php:29
+#: data/templates/dynamictags.inc.php:128
+#: data/templates/sidebar.block.common.php:9
+#: data/templates/sidebar.block.menu.php:74
+#: data/templates/sidebar.block.popular.php:23
+#: data/templates/sidebar.block.recent.php:34
+#: data/templates/toolbar.inc.php:27 www/populartags.php:46
+msgid "Popular Tags"
+msgstr "Mots-cl&eacute;s populaires"
+
+#: data/templates/dynamictags.inc.php:131
+#, fuzzy
+msgid "Popular Tags From All Users"
+msgstr "Mots-cl&eacute;s populaires"
+
+#: data/templates/editbookmark.tpl.php:38
msgid "Address"
msgstr "Adresse"
-#: ../../../templates/editbookmark.tpl.php:31
-#: ../../../templates/editbookmark.tpl.php:36
-#: ../../../templates/editprofile.tpl.php:30
-#: ../../../templates/tagrename.tpl.php:14
-#: ../../../templates/tagrename.tpl.php:19
+#: data/templates/editbookmark.tpl.php:40
+#: data/templates/editbookmark.tpl.php:45
+#: data/templates/editprofile.tpl.php:31 data/templates/tagrename.tpl.php:14
+#: data/templates/tagrename.tpl.php:19
msgid "Required"
msgstr "Requis"
-#: ../../../templates/editbookmark.tpl.php:46
+#: data/templates/editbookmark.tpl.php:50
+msgid "Add Note"
+msgstr ""
+
+#: data/templates/editbookmark.tpl.php:53
+msgid ""
+"You can use anchors to delimite attributes. for example: [publisher]blah[/"
+"publisher] "
+msgstr ""
+
+#: data/templates/editbookmark.tpl.php:56
+msgid "Suggested anchors: "
+msgstr ""
+
+#: data/templates/editbookmark.tpl.php:68
+#, fuzzy
+msgid "Private Note"
+msgstr "Privée"
+
+#: data/templates/editbookmark.tpl.php:70
+msgid "Just visible by you and your contacts."
+msgstr ""
+
+#: data/templates/editbookmark.tpl.php:74 data/templates/toolbar.inc.php:10
+#: www/tags.php:45 www/tags.php:67
+msgid "Tags"
+msgstr "Mots-clés"
+
+#: data/templates/editbookmark.tpl.php:78
msgid "Comma-separated"
msgstr "Séparés par des virgules"
-#: ../../../templates/editbookmark.tpl.php:50
-#: ../../../templates/tag2tagadd.tpl.php:9
-msgid "Note: use \">\" to include one tag in another. e.g.: europe>france>paris"
-msgstr "Note: utiliser \">\" pour inclure un mot-cl&eacute; dans un autre. ex: europe>france>paris"
+#: data/templates/editbookmark.tpl.php:82 data/templates/tag2tagadd.tpl.php:9
+msgid ""
+"Note: use \">\" to include one tag in another. e.g.: europe>france>paris"
+msgstr ""
+"Note: utiliser \">\" pour inclure un mot-cl&eacute; dans un autre. ex: "
+"europe>france>paris"
-#: ../../../templates/editbookmark.tpl.php:54
-#: ../../../templates/mot-cl&eacute;2tagadd.tpl.php:8
+#: data/templates/editbookmark.tpl.php:86 data/templates/tag2tagadd.tpl.php:8
msgid "Note: use \"=\" to make synonym two tags. e.g.: france=frenchcountry"
-msgstr "Note : utiliser \"=\" pour rendre deux mots-cl&eacute;s synonymes ex: europe=eu"
+msgstr ""
+"Note : utiliser \"=\" pour rendre deux mots-cl&eacute;s synonymes ex: "
+"europe=eu"
-#: ../../../templates/editbookmark.tpl.php:57
-#: ../../../templates/importDelicious.tpl.php:15
-#: ../../../templates/importNetscape.tpl.php:16
+#: data/templates/editbookmark.tpl.php:89
+#: data/templates/importDelicious.tpl.php:15
+#: data/templates/importNetscape.tpl.php:16
msgid "Privacy"
msgstr "Vision"
-#: ../../../templates/editbookmark.tpl.php:60
-#: ../../../templates/importDelicious.tpl.php:18
-#: ../../../templates/importNetscape.tpl.php:19
+#: data/templates/editbookmark.tpl.php:92
+#: data/templates/importDelicious.tpl.php:18
+#: data/templates/importNetscape.tpl.php:19
msgid "Public"
msgstr "Publique"
-#: ../../../templates/editbookmark.tpl.php:61
+#: data/templates/editbookmark.tpl.php:93
msgid "Shared with Watch List"
msgstr "Partagé avec liste d'accès"
-#: ../../../templates/editbookmark.tpl.php:62
-#: ../../../templates/importDelicious.tpl.php:20
-#: ../../../templates/importNetscape.tpl.php:21
+#: data/templates/editbookmark.tpl.php:94
+#: data/templates/importDelicious.tpl.php:20
+#: data/templates/importNetscape.tpl.php:21
msgid "Private"
msgstr "Privée"
-#: ../../../templates/editbookmark.tpl.php:74
+#: data/templates/editbookmark.tpl.php:107
msgid "Delete Bookmark"
msgstr "Supprimer le signet"
-#: ../../../templates/editbookmark.tpl.php:101
+#: data/templates/editbookmark.tpl.php:112
+msgid "edit common description"
+msgstr "éditer la description commune"
+
+#: data/templates/editbookmark.tpl.php:139
msgid "Bookmarklet"
msgstr "Bookmarklet"
-#: ../../../templates/editbookmark.tpl.php:102
+#: data/templates/editbookmark.tpl.php:145
+#, fuzzy, php-format
+msgid ""
+"Click one of the following bookmarklets to add a button you can click "
+"whenever you want to add the page you are on to %s"
+msgstr ""
+"Déplacez l'un des 'bookmarklet' suivants dans les marques-pages de votre "
+"navigateur et cliquez dessus chaque fois que vous souhaitez ajouter un "
+"signet pour la page courante dans %s "
+
+#: data/templates/editbookmark.tpl.php:149
#, php-format
-msgid "Drag one of the following bookmarklets to your browser's bookmarks and click it whenever you want to add the page you are on to %s"
-msgstr "Déplacez l'un des 'bookmarklet' suivants dans les marques-pages de votre navigateur et cliquez dessus chaque fois que vous souhaitez ajouter un signet pour la page courante dans %s "
+msgid ""
+"Drag one of the following bookmarklets to your browser's bookmarks and click "
+"it whenever you want to add the page you are on to %s"
+msgstr ""
+"Déplacez l'un des 'bookmarklet' suivants dans les marques-pages de votre "
+"navigateur et cliquez dessus chaque fois que vous souhaitez ajouter un "
+"signet pour la page courante dans %s "
-#: ../../../templates/editbookmark.tpl.php:114
+#: data/templates/editbookmark.tpl.php:162
+#: data/templates/editbookmark.tpl.php:167
#, php-format
msgid "Post to %s"
msgstr "Ajouter à %s"
-#: ../../../templates/editbookmark.tpl.php:115
+#: data/templates/editbookmark.tpl.php:163
+#: data/templates/editbookmark.tpl.php:168
#, php-format
msgid "Post to %s (Pop-up)"
msgstr "Ajouter à %s (Pop-up)"
-#: ../../../templates/editbookmark.tpl.php:119
-#: ../../../templates/importDelicious.tpl.php:26
-#: ../../../templates/importNetscape.tpl.php:27
+#: data/templates/editbookmark.tpl.php:173
+#: data/templates/importDelicious.tpl.php:26
+#: data/templates/importNetscape.tpl.php:27
+#: data/templates/importStructure.tpl.php:16
msgid "Import"
msgstr "Importer"
-#: ../../../templates/editbookmark.tpl.php:121
+#: data/templates/editbookmark.tpl.php:175
msgid "Import bookmarks from bookmark file"
msgstr "Importer les signets depuis un fichier"
-#: ../../../templates/editbookmark.tpl.php:121
+#: data/templates/editbookmark.tpl.php:175
msgid "Internet Explorer, Mozilla Firefox and Netscape"
msgstr "Internet Explorer, Mozilla Firefox et Netscape"
-#: ../../../templates/editbookmark.tpl.php:122
+#: data/templates/editbookmark.tpl.php:176
msgid "Import bookmarks from del.icio.us"
msgstr "Importer les signets depuis del.icio.us"
-#: ../../../templates/editprofile.tpl.php:9
+#: data/templates/editprofile.tpl.php:10
msgid "Account Details"
msgstr "Détail du compte"
-#: ../../../templates/editprofile.tpl.php:13
-#: ../../../templates/login.tpl.php:15
-#: ../../../templates/password.tpl.php:10
-#: ../../../templates/profile.tpl.php:7
-#: ../../../templates/register.tpl.php:16
+#: data/templates/editprofile.tpl.php:14 data/templates/login.tpl.php:21
+#: data/templates/password.tpl.php:10 data/templates/profile.tpl.php:6
+#: data/templates/register.tpl.php:16
msgid "Username"
msgstr "Nom d'utilisateur"
-#: ../../../templates/editprofile.tpl.php:18
+#: data/templates/editprofile.tpl.php:19
msgid "New Password"
msgstr "Nouveau mot de passe"
-#: ../../../templates/editprofile.tpl.php:23
+#: data/templates/editprofile.tpl.php:24
msgid "Confirm Password"
msgstr "Confirmer le mot de passe"
-#: ../../../templates/editprofile.tpl.php:28
-#: ../../../templates/password.tpl.php:14
-#: ../../../templates/register.tpl.php:26
+#: data/templates/editprofile.tpl.php:29 data/templates/password.tpl.php:14
+#: data/templates/register.tpl.php:26
msgid "E-mail"
msgstr "E-mail"
-#: ../../../templates/editprofile.tpl.php:34
+#: data/templates/editprofile.tpl.php:35
msgid "Personal Details"
msgstr "Détails personnels"
-#: ../../../templates/editprofile.tpl.php:38
-#: ../../../templates/profile.tpl.php:12
+#: data/templates/editprofile.tpl.php:39 data/templates/profile.tpl.php:17
msgid "Name"
msgstr "Nom"
-#: ../../../templates/editprofile.tpl.php:42
-#: ../../../templates/profile.tpl.php:18
+#: data/templates/editprofile.tpl.php:43 data/templates/profile.tpl.php:23
msgid "Homepage"
msgstr "Page personnelle"
-#: ../../../templates/editprofile.tpl.php:54
-#: ../../../templates/sidebar.block.tagactions.php:18
-#: ../../../templates/sidebar.block.watchstatus.php:17
+#: data/templates/editprofile.tpl.php:52 www/edit.php:113
+msgid "Save Changes"
+msgstr "Enregistrer les modifications"
+
+#: data/templates/editprofile.tpl.php:55
+#: data/templates/sidebar.block.tagactions.php:17
+#: data/templates/sidebar.block.watchstatus.php:18
#, fuzzy
msgid "Actions"
msgstr "Instructions"
-#: ../../../templates/editprofile.tpl.php:57
+#: data/templates/editprofile.tpl.php:58
msgid "Export bookmarks"
msgstr "Exporter les signets"
-#: ../../../templates/editprofile.tpl.php:59
+#: data/templates/editprofile.tpl.php:60
msgid "HTML file (for browsers)"
msgstr "Fichier HTML (pour navigateurs)"
-#: ../../../templates/editprofile.tpl.php:60
+#: data/templates/editprofile.tpl.php:61
msgid "XML file (like del.icio.us)"
msgstr "Fichier XML (comme del.icio.us)"
-#: ../../../templates/error.404.tpl.php:5
+#: data/templates/editprofile.tpl.php:62
+msgid "CSV file (for spreadsheet tools)"
+msgstr "Fichier CSV (pour les classeurs)"
+
+#: data/templates/error.404.tpl.php:5
msgid "Not Found"
msgstr "Non trouvé"
-#: ../../../templates/error.404.tpl.php:6
+#: data/templates/error.404.tpl.php:6
msgid "The requested URL was not found on this server"
msgstr "L'URL demandée n'a pas été trouvée sur ce serveur."
-#: ../../../templates/error.500.tpl.php:5
+#: data/templates/error.500.tpl.php:5
msgid "General server error"
msgstr "Erreur généralisée du serveur."
-#: ../../../templates/error.500.tpl.php:6
+#: data/templates/error.500.tpl.php:6
msgid "The requested URL could not be processed"
msgstr "L'URL demandée n'a pas été trouvée."
-#: ../../../templates/importDelicious.tpl.php:19
-#: ../../../templates/importNetscape.tpl.php:20
+#: data/templates/importDelicious.tpl.php:19
+#: data/templates/importNetscape.tpl.php:20
#, fuzzy
msgid "Shared with Watchlist"
msgstr "Partagé avec liste d'accès"
-#: ../../../templates/importDelicious.tpl.php:31
-#: ../../../templates/importNetscape.tpl.php:32
+#: data/templates/importDelicious.tpl.php:31
+#: data/templates/importNetscape.tpl.php:32
+#: data/templates/importStructure.tpl.php:21
msgid "Instructions"
msgstr "Instructions"
-#: ../../../templates/importDelicious.tpl.php:33
-msgid "Log in to the <a href=\"http://del.icio.us/api/posts/all\">export page at del.icio.us</a>"
-msgstr "Se connecter à la <a href=\"http://del.icio.us/api/posts/all\">page d'export de del.icio.us</a>"
+#: data/templates/importDelicious.tpl.php:33
+msgid ""
+"Log in to the <a href=\"http://del.icio.us/api/posts/all\">export page at "
+"del.icio.us</a>"
+msgstr ""
+"Se connecter à la <a href=\"http://del.icio.us/api/posts/all\">page d'export "
+"de del.icio.us</a>"
-#: ../../../templates/importDelicious.tpl.php:34
-msgid "Save the resulting <abbr title=\"Extensible Markup Language\">XML</abbr> file to your computer"
-msgstr "Enregistrer le fichier <abbr title=\"Extensible Markup Language\">XML</abbr> résultant sur votre ordinateur"
+#: data/templates/importDelicious.tpl.php:34
+msgid ""
+"Save the resulting <abbr title=\"Extensible Markup Language\">XML</abbr> "
+"file to your computer"
+msgstr ""
+"Enregistrer le fichier <abbr title=\"Extensible Markup Language\">XML</abbr> "
+"résultant sur votre ordinateur"
-#: ../../../templates/importDelicious.tpl.php:35
-msgid "Click <kbd>Browse...</kbd> to find this file on your computer. The maximum size the file can be is 1MB"
-msgstr "Cliquez sur <kbd>Parcourir...</kbd> pour trouver le fichier sur votre ordinateur. La taille maximale du fichier ne peut excèder 1Mo"
+#: data/templates/importDelicious.tpl.php:35
+msgid ""
+"Click <kbd>Browse...</kbd> to find this file on your computer. The maximum "
+"size the file can be is 1MB"
+msgstr ""
+"Cliquez sur <kbd>Parcourir...</kbd> pour trouver le fichier sur votre "
+"ordinateur. La taille maximale du fichier ne peut excèder 1Mo"
-#: ../../../templates/importDelicious.tpl.php:36
-#: ../../../templates/importNetscape.tpl.php:43
+#: data/templates/importDelicious.tpl.php:36
+#: data/templates/importNetscape.tpl.php:43
msgid "Select the default privacy setting for your imported bookmarks"
msgstr "Selectionnez la vision par défaut à appliquer à vos signets importés"
-#: ../../../templates/importDelicious.tpl.php:37
-#: ../../../templates/importNetscape.tpl.php:44
-msgid "Click <kbd>Import</kbd> to start importing the bookmarks; it may take a minute"
-msgstr "Cliquez sur <kbd>Importer</kbd> pour débuter l'import des signets; cette opération peut prendre quelques minutes"
+#: data/templates/importDelicious.tpl.php:37
+#: data/templates/importNetscape.tpl.php:44
+msgid ""
+"Click <kbd>Import</kbd> to start importing the bookmarks; it may take a "
+"minute"
+msgstr ""
+"Cliquez sur <kbd>Importer</kbd> pour débuter l'import des signets; cette "
+"opération peut prendre quelques minutes"
-#: ../../../templates/importNetscape.tpl.php:35
+#: data/templates/importNetscape.tpl.php:35
msgid "Export your bookmarks from your browser to a file"
msgstr "Exporter vos signets dans un fichier depuis votre navigateur"
-#: ../../../templates/importNetscape.tpl.php:37
-msgid "Internet Explorer: <kbd>File &gt; Import and Export... &gt; Export Favorites"
-msgstr "Internet Explorer: <kbd>Ficher &gt; Importer et Exporter... &gt; Exporter les favoris"
+#: data/templates/importNetscape.tpl.php:37
+msgid ""
+"Internet Explorer: <kbd>File &gt; Import and Export... &gt; Export Favorites"
+msgstr ""
+"Internet Explorer: <kbd>Ficher &gt; Importer et Exporter... &gt; Exporter "
+"les favoris"
-#: ../../../templates/importNetscape.tpl.php:38
-msgid "Mozilla Firefox: <kbd>Bookmarks &gt; Manage Bookmarks... &gt; File &gt; Export..."
-msgstr "Mozilla Firefox: <kbd>Marques-pages &gt; Gérer les marques-pages... &gt; Fichier &gt; Exporter..."
+#: data/templates/importNetscape.tpl.php:38
+msgid ""
+"Mozilla Firefox: <kbd>Bookmarks &gt; Manage Bookmarks... &gt; File &gt; "
+"Export..."
+msgstr ""
+"Mozilla Firefox: <kbd>Marques-pages &gt; Gérer les marques-pages... &gt; "
+"Fichier &gt; Exporter..."
-#: ../../../templates/importNetscape.tpl.php:39
-msgid "Netscape: <kbd>Bookmarks &gt; Manage Bookmarks... &gt; Tools &gt; Export..."
-msgstr "Netscape: <kbd>Marques-pages &gt; Gérer les marques-pages... &gt; Outils &gt; Exporter..."
+#: data/templates/importNetscape.tpl.php:39
+msgid ""
+"Netscape: <kbd>Bookmarks &gt; Manage Bookmarks... &gt; Tools &gt; Export..."
+msgstr ""
+"Netscape: <kbd>Marques-pages &gt; Gérer les marques-pages... &gt; Outils "
+"&gt; Exporter..."
+
+#: data/templates/importNetscape.tpl.php:42
+msgid ""
+"Click <kbd>Browse...</kbd> to find the saved bookmark file on your computer. "
+"The maximum size the file can be is 1MB"
+msgstr ""
+"Cliquez sur <kbd>Parcourir...</kbd> pour trouver le fichier sur votre "
+"ordinateur. La taille maximale du fichier ne peut excèder 1Mo"
-#: ../../../templates/importNetscape.tpl.php:42
-msgid "Click <kbd>Browse...</kbd> to find the saved bookmark file on your computer. The maximum size the file can be is 1MB"
-msgstr "Cliquez sur <kbd>Parcourir...</kbd> pour trouver le fichier sur votre ordinateur. La taille maximale du fichier ne peut excèder 1Mo"
+#: data/templates/importStructure.tpl.php:24
+msgid "Create your structure into a simple text file and following this model:"
+msgstr ""
+
+#: data/templates/importStructure.tpl.php:35
+msgid ""
+"Then import the file. The tags and their relations will be added to your "
+"profile."
+msgstr ""
+
+#: data/templates/login.tpl.php:13
+msgid "Please activate cookies"
+msgstr ""
-#: ../../../templates/login.tpl.php:20
-#: ../../../templates/register.tpl.php:21
+#: data/templates/login.tpl.php:26 data/templates/register.tpl.php:21
msgid "Password"
msgstr "Mot de passe"
-#: ../../../templates/login.tpl.php:22
+#: data/templates/login.tpl.php:28
msgid "Don't ask for my password for 2 weeks"
msgstr "Ne pas demander mon mot de passe pendant 2 semaines"
-#: ../../../templates/login.tpl.php:30
+#: data/templates/login.tpl.php:32 data/templates/toolbar.inc.php:29
+#: www/login.php:57
+msgid "Log In"
+msgstr "Se connecter"
+
+#: data/templates/login.tpl.php:36
msgid "Forgotten your password?"
msgstr "Avez-vous oublié votre mot de passe ?"
-#: ../../../templates/password.tpl.php:5
+#: data/templates/password.tpl.php:5
#, php-format
-msgid "If you have forgotten your password, %s can generate a new one. Enter the username and e-mail address of your account into the form below and we will e-mail your new password to you."
-msgstr "Si vous avez oublié votre mot de passe, %s peut en générer un nouveau. Entrez le nom d'utilisateur et l'adresse email de votre compte dans le formulaire ci-dessous et nous vous enverrons un nouveau mot de passe."
+msgid ""
+"If you have forgotten your password, %s can generate a new one. Enter the "
+"username and e-mail address of your account into the form below and we will "
+"e-mail your new password to you."
+msgstr ""
+"Si vous avez oublié votre mot de passe, %s peut en générer un nouveau. "
+"Entrez le nom d'utilisateur et l'adresse email de votre compte dans le "
+"formulaire ci-dessous et nous vous enverrons un nouveau mot de passe."
-#: ../../../templates/password.tpl.php:19
+#: data/templates/password.tpl.php:19
msgid "Generate Password"
msgstr "Générer un mot de passe"
-#: ../../../templates/profile.tpl.php:23
+#: data/templates/profile.tpl.php:11
+#, fuzzy
+msgid "Email"
+msgstr "E-mail"
+
+#: data/templates/profile.tpl.php:28
msgid "Member Since"
msgstr "Membre depuis"
-#: ../../../templates/profile.tpl.php:35
-#: ../../../templates/sidebar.block.watchlist.php:8
+#: data/templates/profile.tpl.php:40
+#: data/templates/sidebar.block.watchlist.php:30
#, fuzzy
msgid "Watching"
-msgstr "Liste des signets vus"
+msgstr "Él&eacute;ments surveill&eacute;s"
-#: ../../../templates/profile.tpl.php:50
+#: data/templates/profile.tpl.php:55
+#: data/templates/sidebar.block.watchlist.php:52
#, fuzzy
msgid "Watched By"
-msgstr "Consultés"
+msgstr "Surveill&eacute; par"
-#: ../../../templates/profile.tpl.php:63
-#: ../../../templates/toolbar.inc.php:10
+#: data/templates/profile.tpl.php:68 data/templates/toolbar.inc.php:9
msgid "Bookmarks"
msgstr "Signets"
-#: ../../../templates/profile.tpl.php:64
+#: data/templates/profile.tpl.php:69
msgid "Go to bookmarks"
msgstr "Aller aux signets"
-#: ../../../templates/register.tpl.php:11
+#: data/templates/register.tpl.php:11
#, php-format
-msgid "Sign up here to create a free %s account. All the information requested below is required"
-msgstr "Enregistrez-vous ici pour créer un compte gratuit %s. Toutes les informations requises ci-dessous sont nécessaires."
+msgid ""
+"Sign up here to create a free %s account. All the information requested "
+"below is required"
+msgstr ""
+"Enregistrez-vous ici pour créer un compte gratuit %s. Toutes les "
+"informations requises ci-dessous sont nécessaires."
+
+#: data/templates/register.tpl.php:18
+msgid ""
+" at least 5 characters, alphanumeric (no spaces, no dots or other special "
+"ones)"
+msgstr ""
-#: ../../../templates/register.tpl.php:33
+#: data/templates/register.tpl.php:28
+msgid " to send you your password if you forget it"
+msgstr ""
+
+#: data/templates/register.tpl.php:33
msgid "Antispam question"
msgstr "Question antispam"
-#: ../../../templates/sidebar.block.linked.php:41
+#: data/templates/register.tpl.php:41 data/templates/toolbar.inc.php:31
+#: www/register.php:83
+msgid "Register"
+msgstr "S'enregistrer"
+
+#: data/templates/search.menu.php:27
+#, fuzzy
+msgid "Search..."
+msgstr "Chercher dans"
+
+#: data/templates/search.menu.php:28
+#, fuzzy
+msgid "in"
+msgstr "Ligne"
+
+#: data/templates/search.menu.php:34
+msgid "this user's bookmarks"
+msgstr "les signets de cet utilisateur"
+
+#: data/templates/search.menu.php:39
+msgid "my bookmarks"
+msgstr "mes signets"
+
+#: data/templates/search.menu.php:40
+msgid "my watchlist"
+msgstr "ma liste de suivi"
+
+#: data/templates/search.menu.php:44
+msgid "all bookmarks"
+msgstr "tous les signets"
+
+#: data/templates/search.menu.php:54
+msgid "Search"
+msgstr "Chercher dans"
+
+#: data/templates/sidebar.block.linked.php:51
msgid "Linked Tags"
msgstr "Mots-cl&eacute;s structurés"
-#: ../../../templates/sidebar.block.linked.php:55
-#: ../../../templates/sidebar.block.menu.php:40
+#: data/templates/sidebar.block.linked.php:62
+#: data/templates/sidebar.block.menu.php:46
msgid "Add new link"
msgstr "Créer un lien"
-#: ../../../templates/sidebar.block.linked.php:56
-#: ../../../templates/sidebar.block.menu.php:41
+#: data/templates/sidebar.block.linked.php:63
+#: data/templates/sidebar.block.menu.php:47
msgid "Delete link"
msgstr "Supprimer un lien"
-#: ../../../templates/sidebar.block.menu.php:29
+#: data/templates/sidebar.block.menu.php:35
#, php-format
msgid "Tags included into the tag '%s'"
msgstr "Mots-cl&eacute;s inclus dans le mot-cl&eacute; '%s'"
-#: ../../../templates/sidebar.block.menu.php:29
+#: data/templates/sidebar.block.menu.php:35
msgid "Menu Tags"
msgstr "Mots-cl&eacute;s Menu"
-#: ../../../templates/sidebar.block.menu.php:62
+#: data/templates/sidebar.block.menu.php:68
msgid "See all your tags"
msgstr "Voir tous vos mots-cl&eacute;s"
-#: ../../../templates/sidebar.block.menu.php:62
+#: data/templates/sidebar.block.menu.php:68
msgid "all your tags"
msgstr "Tous vos mots-cl&eacute;s"
-#: ../../../templates/sidebar.block.menu.php:64
+#: data/templates/sidebar.block.menu.php:70
msgid "See all tags from this user"
msgstr "Voir tous les mots-cl&eacute;s de cet utilisateur"
-#: ../../../templates/sidebar.block.menu.php:64
+#: data/templates/sidebar.block.menu.php:70
msgid "all tags from this user"
msgstr "tous les mots-cl&eacute;s de cet utilisateur"
-#: ../../../templates/sidebar.block.menu.php:68
+#: data/templates/sidebar.block.menu.php:74
#, fuzzy
msgid "See popular tags"
msgstr "Voir tous vos mots-cl&eacute;s"
-#: ../../../templates/sidebar.block.recent.php:15
+#: data/templates/sidebar.block.menu2.php:25
+#, fuzzy
+msgid "Featured Menu Tags"
+msgstr "Mots-cl&eacute;s Menu"
+
+#: data/templates/sidebar.block.menu2.php:29
+msgid "This menu is composed of keywords (tags) organized by admins."
+msgstr ""
+
+#: data/templates/sidebar.block.recent.php:18
msgid "Recent Tags"
msgstr "Mots-cl&eacute;s récents"
-#: ../../../templates/sidebar.block.related.php:17
+#: data/templates/sidebar.block.related.php:26
msgid "Related Tags"
msgstr "Mots-cl&eacute;s en relation"
-#: ../../../templates/sidebar.block.search.php:15
+#: data/templates/sidebar.block.search.php:15
msgid "Last Searches"
msgstr "Dernières recherches"
-#: ../../../templates/sidebar.block.search.php:24
+#: data/templates/sidebar.block.search.php:24
msgid "Number of bookmarks for this query"
msgstr "Nombre de signets pour cette recherche"
-#: ../../../templates/sidebar.block.tagactions.php:29
+#: data/templates/sidebar.block.tagactions.php:9 www/tagrename.php:72
+msgid "Rename Tag"
+msgid_plural "Rename Tags"
+msgstr[0] "Renommer le mot-cl&eacute;"
+msgstr[1] "Renommer les mots-cl&eacute;s"
+
+#: data/templates/sidebar.block.tagactions.php:22 www/tagdelete.php:54
+msgid "Delete Tag"
+msgstr "Supprimer le mot-cl&eacute;"
+
+#: data/templates/sidebar.block.tagactions.php:24 www/tagedit.php:61
+msgid "Edit Tag Description"
+msgstr "Editer la description du mot-cl&eacute;"
+
+#: data/templates/sidebar.block.tagactions.php:26
+#: www/tagcommondescriptionedit.php:76
+msgid "Edit Tag Common Description"
+msgstr "Editer la description commune du mot-cl&eacute;"
+
+#: data/templates/sidebar.block.tagactions.php:28
msgid "Create a link to another tag"
msgstr "Créer un lien vers un autre mot-cl&eacute;"
-#: ../../../templates/sidebar.block.users.php:13
-msgid "Last Users"
-msgstr "Derniers utilisateurs"
+#: data/templates/sidebar.block.users.php:14
+#, fuzzy
+msgid "New Users"
+msgstr "Utilisateurs"
-#: ../../../templates/sidebar.block.users.php:22
-#: ../../../templates/users.tpl.php:17
+#: data/templates/sidebar.block.users.php:23 data/templates/users.tpl.php:17
msgid "bookmarks"
msgstr "signets"
-#: ../../../templates/sidebar.block.users.php:29
+#: data/templates/sidebar.block.users.php:30
#, fuzzy
msgid "See all users"
msgstr "Voir tous vos mots-cl&eacute;s"
-#: ../../../templates/sidebar.block.users.php:29
+#: data/templates/sidebar.block.users.php:30
msgid "All users"
msgstr "Tous les utilisateurs"
-#: ../../../templates/sidebar.block.watchstatus.php:10
+#: data/templates/sidebar.block.watchlist.php:19
+msgid "Close contacts are mutual contacts"
+msgstr ""
+
+#: data/templates/sidebar.block.watchlist.php:19
+msgid "Close contacts"
+msgstr ""
+
+#: data/templates/sidebar.block.watchlist.php:36
+msgid "Add a contact..."
+msgstr ""
+
+#: data/templates/sidebar.block.watchlist.php:36
+msgid "Type a username to add it to your contacts."
+msgstr ""
+
+#: data/templates/sidebar.block.watchlist.php:44
+#, fuzzy
+msgid "Remove this contact"
+msgstr "Enlever de la liste des consultés"
+
+#: data/templates/sidebar.block.watchstatus.php:11
msgid "Remove from Watchlist"
msgstr "Enlever de la liste des consultés"
-#: ../../../templates/sidebar.block.watchstatus.php:12
+#: data/templates/sidebar.block.watchstatus.php:13
msgid "Add to Watchlist"
msgstr "Ajouter à la liste des consultés"
-#: ../../../templates/sidebar.linkedtags.inc.php:18
+#: data/templates/sidebar.linkedtags.inc.php:18
msgid "Edit link"
msgstr "Editer un lien"
-#: ../../../templates/sidebar.linkedtags.inc.php:45
+#: data/templates/sidebar.linkedtags.inc.php:47
msgid "Synonyms:"
msgstr "Synonymes :"
-#: ../../../templates/tag2tagadd.tpl.php:12
+#: data/templates/tag2tagadd.tpl.php:12
msgid "Create new link:"
msgstr "Créer un nouveau lien"
-#: ../../../templates/tag2tagadd.tpl.php:19
+#: data/templates/tag2tagadd.tpl.php:19
#, php-format
-msgid "Note: include a tag into '%s' tag (e.g. %s>countries) display the tag into the menu box"
-msgstr "Note : inclure un mot-cl&eacute; dans le mot-cl&eacute; '%s' (e.g. %s>countries) affiche ce mot-cl&eacute; dans la boîte de menu"
+msgid ""
+"Note: include a tag into '%s' tag (e.g. %s>countries) display the tag into "
+"the menu box"
+msgstr ""
+"Note : inclure un mot-cl&eacute; dans le mot-cl&eacute; '%s' (e.g. %"
+"s>countries) affiche ce mot-cl&eacute; dans la boîte de menu"
-#: ../../../templates/tag2tagadd.tpl.php:23
-#: ../../../templates/tag2tagedit.tpl.php:37
+#: data/templates/tag2tagadd.tpl.php:23 data/templates/tag2tagedit.tpl.php:37
msgid "Create"
msgstr "Créer"
-#: ../../../templates/tag2tagadd.tpl.php:35
-#: ../../../templates/tag2tagdelete.tpl.php:27
-#: ../../../templates/tag2tagedit.tpl.php:51
+#: data/templates/tag2tagadd.tpl.php:35
+#: data/templates/tag2tagdelete.tpl.php:27
+#: data/templates/tag2tagedit.tpl.php:51
msgid "Existing links:"
msgstr "Liens existants :"
-#: ../../../templates/tag2tagadd.tpl.php:53
-#: ../../../templates/tag2tagdelete.tpl.php:45
-#: ../../../templates/tag2tagedit.tpl.php:69
+#: data/templates/tag2tagadd.tpl.php:53
+#: data/templates/tag2tagdelete.tpl.php:45
+#: data/templates/tag2tagedit.tpl.php:69
msgid "No links"
msgstr "Pas de liens"
-#: ../../../templates/tag2tagedit.tpl.php:6
+#: data/templates/tag2tagdelete.tpl.php:15
+#: data/templates/tag2tagedit.tpl.php:16 data/templates/tagdelete.tpl.php:8
+#: www/jsScuttle.php:23
+msgid "Yes"
+msgstr "Oui"
+
+#: data/templates/tag2tagdelete.tpl.php:16
+#: data/templates/tag2tagedit.tpl.php:17 data/templates/tagdelete.tpl.php:9
+#: www/jsScuttle.php:23
+msgid "No"
+msgstr "Non"
+
+#: data/templates/tag2tagedit.tpl.php:6
msgid "Delete the link"
msgstr "Supprimer le lien"
-#: ../../../templates/tag2tagedit.tpl.php:29
+#: data/templates/tag2tagedit.tpl.php:29
msgid "Create new link"
msgstr "Créer un nouveau lien"
-#: ../../../templates/tagrename.tpl.php:12
+#: data/templates/tagrename.tpl.php:12
msgid "Old"
msgstr "Ancien"
-#: ../../../templates/tagrename.tpl.php:17
+#: data/templates/tagrename.tpl.php:17
msgid "New"
msgstr "Nouveau"
-#: ../../../templates/tagrename.tpl.php:24
+#: data/templates/tagrename.tpl.php:24
msgid "Rename"
msgstr "Renommer"
-#: ../../../templates/tags.tpl.php:11
-#: ../../../templates/users.tpl.php:9
+#: data/templates/tags.tpl.php:11 data/templates/users.tpl.php:9
msgid "Alphabet"
msgstr "Alphabet"
-#: ../../../templates/tags.tpl.php:12
-#: ../../../templates/users.tpl.php:10
+#: data/templates/tags.tpl.php:12 data/templates/users.tpl.php:10
msgid "Popularity"
msgstr "Popularité"
-#: ../../../templates/toolbar.inc.php:15
+#: data/templates/toolbar.inc.php:8 data/templates/toolbar.inc.php:26
+#, fuzzy
+msgid "Home"
+msgstr "Page personnelle"
+
+#: data/templates/toolbar.inc.php:11 www/watchlist.php:106
+#, fuzzy
+msgid "Watchlist"
+msgstr "Liste des signets vus"
+
+#: data/templates/toolbar.inc.php:12 www/profile.php:67
+msgid "Profile"
+msgstr "Profil"
+
+#: data/templates/toolbar.inc.php:13 www/bookmarks.php:209
+msgid "Add a Bookmark"
+msgstr "Ajouter un signet"
+
+#: data/templates/toolbar.inc.php:14
msgid "Log Out"
msgstr "Quitter"
-#: ../../../templates/users.tpl.php:17
+#: data/templates/toolbar.inc.php:17
+msgid "Admin"
+msgstr ""
+
+#: data/templates/top.inc.php:49
+msgid ""
+"Admins, your installation is in \"Debug Mode\" ($debugMode = true). To go in "
+"\"Normal Mode\" and hide debugging messages, change $debugMode to false into "
+"config.php."
+msgstr ""
+
+#: data/templates/users.tpl.php:17
msgid "profile"
msgstr "Profil"
-#: ../../../templates/users.tpl.php:17
+#: data/templates/users.tpl.php:17
msgid "created in"
msgstr "Créé en "
+#: www/admin.php:32
+msgid "Manage users"
+msgstr ""
+
+#: www/admin.php:68
+#, php-format
+msgid "%s and all his bookmarks and tags were deleted."
+msgstr ""
+
+#: www/admin.php:75
+msgid "Problem with "
+msgstr ""
+
+#: www/ajaxDelete.php:37
+msgid "You are not allowed to delete this bookmark"
+msgstr "Vous n'êtes pas autorisés à supprimer ce signet"
+
+#: www/ajaxDelete.php:41 www/edit.php:103
+msgid "Failed to delete bookmark"
+msgstr "Erreur dans la suppression du signet"
+
+#: www/alltags.php:50
+msgid "All Tags"
+msgstr "Tous les mots-cl&eacute;s"
+
+#: www/alltags.php:56 www/bookmarks.php:96 www/populartags.php:52
+#: www/profile.php:51 www/rss.php:76 www/search.php:109 www/watch.php:45
+#: www/watchlist.php:61
+#, php-format
+msgid "User with username %s was not found"
+msgstr "L'utilisateur %s n'a pas été trouvé."
+
+#: www/bookmarkcommondescriptionedit.php:51 www/tag2tagadd.php:37
+#: www/tag2tagdelete.php:41 www/tag2tagedit.php:33
+#: www/tagcommondescriptionedit.php:51 www/tagedit.php:43
+msgid "Permission denied."
+msgstr "Permission non accordée."
+
+#: www/bookmarkcommondescriptionedit.php:60
+msgid "Bookmark common description updated"
+msgstr "Description commune du signet mise à jour."
+
+#: www/bookmarkcommondescriptionedit.php:63
+msgid "Failed to update the bookmark common description"
+msgstr "Erreur dans la mise à jour de la description du signet"
+
+#: www/bookmarkcommondescriptionedit.php:71
+msgid "Edit Bookmark Common Description"
+msgstr "Editer la description commune du signet"
+
+#: www/bookmarks.php:111 www/tags.php:47
+#, fuzzy
+msgid "Remove the tag from the selection"
+msgstr "Voir tous les mots-cl&eacute;s de cet utilisateur"
+
+#: www/bookmarks.php:131 www/edit.php:65
+msgid "Your bookmark must have a title and an address"
+msgstr "Votre signet doit avoir un titre et une adresse."
+
+#: www/bookmarks.php:152 www/edit.php:83 www/edit.php:86
+msgid "Bookmark saved"
+msgstr "Signet enregistré."
+
+#: www/bookmarks.php:152
+msgid "(Come back to previous page.)"
+msgstr ""
+
+#: www/bookmarks.php:159 www/import.php:106 www/importNetscape.php:108
+msgid ""
+"There was an error saving your bookmark. Please try again or contact the "
+"administrator."
+msgstr ""
+"Il y a eu une erreur en enregistrant ce signet. Veuillez rééssayer ou "
+"contacter votre administrateur."
+
+#: www/bookmarks.php:216
+msgid "Add Bookmark"
+msgstr "Ajouter signet"
+
+#: www/bookmarks.php:219
+msgid "You must be logged in before you can add bookmarks."
+msgstr "Vous devez être authentifié avant de pouvoir ajouter des signets."
+
+#: www/bookmarks.php:274 www/bookmarks.php:275
+msgid "My Bookmarks"
+msgstr "Mes signets"
+
+#: www/edit.php:44 www/edit.php:45
+msgid "Edit Bookmark"
+msgstr "Editer le signet"
+
+#: www/edit.php:51
+#, php-format
+msgid "Bookmark with id %s not was not found"
+msgstr "Signet %s non trouvé"
+
+#: www/edit.php:57
+msgid "You are not allowed to edit this bookmark"
+msgstr "Vous n'êtes pas autorisé à éditer ce signet."
+
+#: www/edit.php:77
+msgid "Error while saving your bookmark"
+msgstr "Erreur pendant l'enregistrement de votre signet."
+
+#: www/history.php:61
+msgid "History"
+msgstr "Historique"
+
+#: www/history.php:62
+#, php-format
+msgid "History for %s"
+msgstr "Historique de %s"
+
+#: www/history.php:84
+msgid "Address was not found"
+msgstr "L'adresse n'a pas été trouvée."
+
+#: www/import.php:47
+msgid "Could not open XML input"
+msgstr "Impossible d'ouvrir le flux XML."
+
+#: www/import.php:51
+#, php-format
+msgid "XML error: %s at line %d"
+msgstr "Erreur XML: %s à la ligne %d"
+
+#: www/import.php:60
+msgid "Import Bookmarks from del.icio.us"
+msgstr "Importer les signet depuis del.icio.us"
+
+#: www/import.php:93
+msgid "You have already submitted this bookmark."
+msgstr "Vous avez déjà enregistré ce signet."
+
+#: www/import.php:104
+msgid "Bookmark imported."
+msgstr "Signet importé."
+
+#: www/importNetscape.php:95
+#, fuzzy
+msgid "You have already submitted some of these bookmarks."
+msgstr "Vous avez déjà enregistré ce signet."
+
+#: www/importNetscape.php:115
+#, fuzzy
+msgid "Bookmarks found: "
+msgstr "Pas de signets trouvés"
+
+#: www/importNetscape.php:116
+#, fuzzy
+msgid "Bookmarks imported: "
+msgstr "Signet importé."
+
+#: www/importNetscape.php:117 www/importNetscape.php:122
+msgid "Import Bookmarks from Browser File"
+msgstr "Importer les signets depuis un fichier"
+
+#: www/importStructure.php:61
+msgid "Bad indentation"
+msgstr ""
+
+#: www/importStructure.php:67
+#, fuzzy
+msgid "New links between tags: "
+msgstr "Effacer un lien entre mots-cl&eacute;s"
+
+#: www/importStructure.php:72
+msgid "Import Structure"
+msgstr ""
+
+#: www/index.php:38
+msgid "You have now logged out"
+msgstr "Vous êtes maintenant déconnecté."
+
+#: www/index.php:45
+#, php-format
+msgid "%s: Recent bookmarks"
+msgstr "%s: Signets récents"
+
+#: www/index.php:75
+msgid "Store, share and tag your favourite links"
+msgstr "Conservez, partagez et libellez vos liens favoris"
+
+#: www/index.php:76
+msgid "All Bookmarks"
+msgstr "Tous les signets"
+
+#: www/jsScuttle.php:70
+msgid "Available"
+msgstr "Disponible"
+
+#: www/jsScuttle.php:73
+msgid "Not Available"
+msgstr "Non Disponible"
+
+#: www/login.php:48
+msgid "The details you have entered are incorrect. Please try again."
+msgstr ""
+"Les informations que vous avez entrées sont incorrectes. Veuillez "
+"recommencer."
+
+#: www/password.php:36
+msgid "You must enter your username."
+msgstr "Vous devez entrer votre nom d'utilisateur."
+
+#: www/password.php:40
+msgid ""
+"You must enter your <abbr title=\"electronic mail\">e-mail</abbr> address."
+msgstr ""
+"Vous <em>devez</em> saisir une <abbr title=\"adresse électronique\">E-mail</"
+"abbr>."
+
+#: www/password.php:48
+msgid "No matches found for that username."
+msgstr "Rien de trouvé pour ce nom d'utilisateur."
+
+#: www/password.php:51
+#, fuzzy
+msgid ""
+"No matches found for that combination of username and <abbr title="
+"\"electronic mail\">e-mail</abbr> address."
+msgstr ""
+"Nous n'avons rien trouvé pour cette combinaison de nom d'utilisateur et "
+"d'<abbr title=\"adresse mail\">e-mail</abbr>."
+
+#: www/password.php:59
+msgid ""
+"There was an error while generating your new password. Please try again."
+msgstr ""
+"Il y a eu une erreur en enregistrant ce signet. Veuillez rééssayer ou "
+"contacter votre administrateur."
+
+#: www/password.php:63
+msgid "Your new password is:"
+msgstr "Votre nouveau mot de passe est:"
+
+#: www/password.php:63
+msgid ""
+"To keep your bookmarks secure, you should change this password in your "
+"profile the next time you log in."
+msgstr ""
+"Pour garder vos signets sûrs, vous devriez changer ce mot de passe dans "
+"votre profil lors de votre prochaine authentification."
+
+#: www/password.php:66
+#, php-format
+msgid "%s Account Information"
+msgstr "Informations du compte de %s"
+
+#: www/password.php:68
+#, php-format
+msgid "New password generated and sent to %s"
+msgstr "Nouveau mot de passe généré et envoyé à l'adresse %s"
+
+#: www/password.php:75
+msgid "Forgotten Password"
+msgstr "Mot de passe oublié"
+
+#: www/profile.php:59 www/watchlist.php:119
+msgid "Username was not specified"
+msgstr "Le nom d'utilisateur n'a pas été spécifié."
+
+#: www/profile.php:65
+msgid "My Profile"
+msgstr "Mon Profil"
+
+#: www/profile.php:89
+msgid "Invalid Token"
+msgstr ""
+
+#: www/profile.php:94
+msgid "Password and confirmation do not match."
+msgstr "Le mot de passe et sa vérification ne correspondent pas."
+
+#: www/profile.php:98
+msgid "Password must be at least 6 characters long."
+msgstr "Le mot de passe doit avoir au moins 6 caractères."
+
+#: www/profile.php:102
+msgid "E-mail address is not valid."
+msgstr "Adresse de courrier électronique invalide."
+
+#: www/profile.php:106
+msgid "An error occurred while saving your changes."
+msgstr ""
+"Une erreur s'est produite pendant l'enregistrement de vos modifications."
+
+#: www/profile.php:108
+msgid "Changes saved."
+msgstr "Modifications enregistrées."
+
+#: www/register.php:46
+msgid "You <em>must</em> enter a username, password and e-mail address."
+msgstr ""
+"Vous <em>devez</em> saisir un nom d'utilisateur, un mot de passe, un nom et "
+"un <abbr title=\"adresse électronique\">e-mail</abbr>"
+
+#: www/register.php:50
+msgid "This username has been reserved, please make another choice."
+msgstr "Ce nom d'utilisateur existe déjà, veuillez en choisir un autre."
+
+#: www/register.php:54
+msgid "This username already exists, please make another choice."
+msgstr "Ce nom d'utilisateur existe déjà, veuillez en choisir un autre."
+
+#: www/register.php:58
+#, fuzzy
+msgid ""
+"This username is not valid (too short, too long, forbidden characters...), "
+"please make another choice."
+msgstr "Ce nom d'utilisateur existe déjà, veuillez en choisir un autre."
+
+#: www/register.php:62
+msgid "E-mail address is not valid. Please try again."
+msgstr "Adresse de courrier électronique invalide. Veuilez réessayer."
+
+#: www/register.php:66
+msgid "Antispam answer is not valid. Please try again."
+msgstr "La réponse antispam n'est pas valide. Veuillez réessayer."
+
+#: www/register.php:75
+msgid "You have successfully registered. Enjoy!"
+msgstr "Votre inscription a bien été prise en compte !"
+
+#: www/register.php:77
+msgid "Registration failed. Please try again."
+msgstr "Enregistrement raté. Veuillez rééssayer."
+
+#: www/rss.php:93
+#, php-format
+msgid "Recent bookmarks posted to %s"
+msgstr "Signets ajoutés récemment à %s"
+
+#: www/search.php:81 www/search.php:145
+msgid "Search Bookmarks"
+msgstr "Recherche de signets"
+
+#: www/search.php:87
+msgid "Search Results"
+msgstr "Résultats de recherche"
+
+#: www/search.php:135
+msgid "Unsatisfied? You can also try our "
+msgstr ""
+
+#: www/tag2tagadd.php:50
+msgid "Tag link created"
+msgstr "Lien entre mot-cl&eacute; créé."
+
+#: www/tag2tagadd.php:53
+msgid "Failed to create the link"
+msgstr "Impossible de créer le lien"
+
+#: www/tag2tagadd.php:65
+msgid "Add Tag Link"
+msgstr "Ajout d'un lien entre mots-cl&eacute;s"
+
+#: www/tag2tagdelete.php:66
+msgid "Tag link deleted"
+msgstr "Effacement d'un lien entre mots-cl&eacute;s"
+
+#: www/tag2tagdelete.php:69
+msgid "Failed to delete the link"
+msgstr "Impossible d'effacer le lien"
+
+#: www/tag2tagdelete.php:81
+msgid "Delete Link Between Tags"
+msgstr "Effacer un lien entre mots-cl&eacute;s"
+
+#: www/tag2tagedit.php:55
+msgid "Edit Link Between Tags"
+msgstr "Editer un lien entre mots-cl&eacute;s"
+
+#: www/tagcommondescriptionedit.php:62
+msgid "Tag common description updated"
+msgstr "Editer la description commune du mot-cl&eacute;"
+
+#: www/tagcommondescriptionedit.php:67
+msgid "Failed to update the tag common description"
+msgstr "Impossible de mettre à jour la description commune du mot-cl&eacute;"
+
+#: www/tagdelete.php:43
+msgid "Tag deleted"
+msgstr "Mot-cl&eacute; effacé"
+
+#: www/tagdelete.php:46
+msgid "Failed to delete the tag"
+msgstr "Impossible d'effacer le mot-cl&eacute;"
+
+#: www/tagedit.php:52
+msgid "Tag description updated"
+msgstr "Description du mot-cl&eacute; mise à jour"
+
+#: www/tagedit.php:55
+msgid "Failed to update the tag description"
+msgstr "Impossible de mettre à jour la description du mot-cl&eacute;"
+
+#: www/tagrename.php:63
+msgid "Tag renamed"
+msgstr "Mot-cl&eacute; renommé"
+
+#: www/tagrename.php:66
+msgid "Failed to rename the tag"
+msgstr "Erreur dans le renommage du mot-cl&eacute;"
+
+#: www/users.php:31
+msgid "Users"
+msgstr "Utilisateurs"
+
+#: www/watch.php:54
+msgid "User removed from your watchlist"
+msgstr "Utilisateur enlevé de votre liste des consultés"
+
+#: www/watch.php:56
+msgid "User added to your watchlist"
+msgstr "Utilisateur ajouté à la liste des consultés."
+
+#: www/watchlist.php:104
+#, fuzzy
+msgid "My Watchlist"
+msgstr "Ma liste de suivi"
+
+#: www/api/httpauth.inc.php:11
+msgid "Use of the API calls requires authentication."
+msgstr ""
+
+#: www/gsearch/index.php:27
+msgid "Come back to "
+msgstr ""
+
+#: www/gsearch/index.php:32
+msgid "Admin tips: "
+msgstr ""
+
+#: www/gsearch/index.php:33
+msgid "To refresh manually Google Custom Search Engine, goes to: "
+msgstr ""
+
+#: www/gsearch/index.php:35
+msgid ""
+"If no result appears, check that all the urls are valid in the admin section."
+msgstr ""
+
+#~ msgid "for"
+#~ msgstr "pour"
+
+#~ msgid "URL"
+#~ msgstr "URL"
+
+msgid "to"
+msgstr "dans"
+
+#~ msgid "Last Users"
+#~ msgstr "Derniers utilisateurs"
+
#~ msgid "Recent Bookmarks"
#~ msgstr "Signets récents"
+
#~ msgid "plus"
#~ msgstr "plus"
+
#~ msgid ""
#~ "<strong><a href=\"register.php\">Register now</a></strong> to start using "
#~ "%s!"
#~ msgstr ""
#~ "<a href=\"register.php\">Enregistrez-vous maintenant</a> pour poster vos "
#~ "propres signets sur %s !"
+
#~ msgid ""
#~ "<a href=\"http://sourceforge.net/projects/semanticscuttle/\">Semantic "
#~ "Scuttle</a> is licensed under the <a href=\"http://www.gnu.org/copyleft/"
@@ -1174,13 +1551,15 @@ msgstr "Créé en "
#~ "Scuttle</a>, sous license <a href=\"http://www.gnu.org/copyleft/gpl.html"
#~ "\"><acronym title=\"GNU's Not Unix\">GNU</acronym> General Public "
#~ "License</a> (vous pouvez donc l'héberger sur votre propre serveur)."
+
#~ msgid "edit"
#~ msgstr "éditer"
+
#~ msgid "User with username %s not was not found"
#~ msgstr "L'utilisateur %s n'a pas été trouvé."
+
#~ msgid "%s Bookmarks"
#~ msgstr "Signets de %s"
+
#~ msgid "<abbr title=\"Electronic mail\">E-mail</abbr>"
#~ msgstr "<abbr title=\"Adresse électronique\">E-mail</abbr>"
-#~ msgid "No bookmarks found"
-#~ msgstr "Pas de signets trouvés"
diff --git a/data/locales/fr_FR/LC_MESSAGES/messages.po b/data/locales/fr_FR/LC_MESSAGES/messages.po
index 396c85e..0aa8be1 100644
--- a/data/locales/fr_FR/LC_MESSAGES/messages.po
+++ b/data/locales/fr_FR/LC_MESSAGES/messages.po
@@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: Scuttle\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2009-11-16 20:55+0100\n"
+"POT-Creation-Date: 2010-09-15 19:15+0200\n"
"PO-Revision-Date: 2009-11-16 21:14+0100\n"
"Last-Translator: BenjaminHKB <benjamin.huynh-kim-bang@loria.fr>\n"
"Language-Team: fr-FR <toony.sf@chezouam.net>\n"
@@ -19,64 +19,76 @@ msgstr ""
"X-Poedit-Country: FRANCE\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
-#: src/SemanticScuttle/functions.php:163
+#: src/SemanticScuttle/functions.php:189
msgid "message_die() was called multiple times."
msgstr "message_die() was called multiple times. ?"
-#: src/SemanticScuttle/functions.php:175
+#: src/SemanticScuttle/functions.php:201
msgid "SQL Error"
msgstr "Erreur SQL"
-#: src/SemanticScuttle/functions.php:181
+#: src/SemanticScuttle/functions.php:207
msgid "Line"
msgstr "Ligne"
-#: src/SemanticScuttle/functions.php:181
+#: src/SemanticScuttle/functions.php:207
#: data/templates/importDelicious.tpl.php:8
#: data/templates/importNetscape.tpl.php:9
#: data/templates/importStructure.tpl.php:10
msgid "File"
msgstr "Fichier"
-#: src/SemanticScuttle/functions.php:189
+#: src/SemanticScuttle/functions.php:215
msgid "Information"
msgstr "Information"
-#: src/SemanticScuttle/functions.php:194
+#: src/SemanticScuttle/functions.php:220
msgid "Critical Information"
msgstr "Information critique."
-#: src/SemanticScuttle/functions.php:199
+#: src/SemanticScuttle/functions.php:225
msgid "An error occured"
msgstr "Une erreur s'est produite."
-#: src/SemanticScuttle/functions.php:202
+#: src/SemanticScuttle/functions.php:228
msgid "General Error"
msgstr "Erreur générale."
-#: src/SemanticScuttle/functions.php:210
+#: src/SemanticScuttle/functions.php:236
msgid "An critical error occured"
msgstr "Une erreur critique s'est produite."
-#: src/SemanticScuttle/functions.php:213
+#: src/SemanticScuttle/functions.php:239
msgid "Critical Error"
msgstr "Erreur critique."
-#: src/SemanticScuttle/functions.php:222
+#: src/SemanticScuttle/functions.php:248
msgid "DEBUG MODE"
msgstr "Mode de débogage."
#: data/templates/about.tpl.php:6
-msgid "<strong>Store</strong> all your favourite links in one place, accessible from anywhere."
-msgstr "<strong>Conservez</strong> tous vos signets au même endroit, accessibles de partout. "
+msgid ""
+"<strong>Store</strong> all your favourite links in one place, accessible "
+"from anywhere."
+msgstr ""
+"<strong>Conservez</strong> tous vos signets au même endroit, accessibles de "
+"partout. "
#: data/templates/about.tpl.php:7
-msgid "<strong>Share</strong> your bookmarks with everyone, with friends on your watchlist or just keep them private."
-msgstr "<strong>Partagez</strong> vos signets avec tout le monde, avec vos contacts ou gardez-les pour vous."
+msgid ""
+"<strong>Share</strong> your bookmarks with everyone, with friends on your "
+"watchlist or just keep them private."
+msgstr ""
+"<strong>Partagez</strong> vos signets avec tout le monde, avec vos contacts "
+"ou gardez-les pour vous."
#: data/templates/about.tpl.php:8
-msgid "<strong>Tag</strong> your bookmarks with as many labels as you want, instead of wrestling with folders."
-msgstr "<strong>Taggez</strong> vos signets avec autant de labels que vous le souhaitez au lieu de les hiérarchiser avec des dossiers."
+msgid ""
+"<strong>Tag</strong> your bookmarks with as many labels as you want, instead "
+"of wrestling with folders."
+msgstr ""
+"<strong>Taggez</strong> vos signets avec autant de labels que vous le "
+"souhaitez au lieu de les hiérarchiser avec des dossiers."
#: data/templates/about.tpl.php:9
msgid "Register now"
@@ -101,8 +113,15 @@ msgstr "vous pouvez librement l'installer sur votre serveur Web"
#: data/templates/about.tpl.php:15
#, php-format
-msgid "%1$s supports most of the <a href=\"http://del.icio.us/doc/api\">del.icio.us <abbr title=\"Application Programming Interface\">API</abbr></a>. Almost all of the neat tools made for that system can be modified to work with %1$s instead. If you find a tool that won't let you change the API address, ask the creator to add this setting. You never know, they might just do it."
-msgstr "%1$s supporte la plupart de l'<a href=\"http://del.icio.us/doc/api\"><abbr title=\"Application Programming Interface\">API</abbr> del.icio.us</a>."
+msgid ""
+"%1$s supports most of the <a href=\"http://del.icio.us/doc/api\">del.icio.us "
+"<abbr title=\"Application Programming Interface\">API</abbr></a>. Almost all "
+"of the neat tools made for that system can be modified to work with %1$s "
+"instead. If you find a tool that won't let you change the API address, ask "
+"the creator to add this setting. You never know, they might just do it."
+msgstr ""
+"%1$s supporte la plupart de l'<a href=\"http://del.icio.us/doc/api\"><abbr "
+"title=\"Application Programming Interface\">API</abbr> del.icio.us</a>."
#: data/templates/about.tpl.php:24
msgid "Tips"
@@ -113,12 +132,18 @@ msgid "Add search plugin into your browser:"
msgstr "Ajouter un plugin de recherche à votre navigateur :"
#: data/templates/about.tpl.php:27
-msgid "The secret tag \"system:unfiled\" allows you to find bookmarks without tags."
-msgstr "Le tag secret \"system:unfiled\" vous permet de trouver les signets sans tags."
+msgid ""
+"The secret tag \"system:unfiled\" allows you to find bookmarks without tags."
+msgstr ""
+"Le tag secret \"system:unfiled\" vous permet de trouver les signets sans "
+"tags."
#: data/templates/about.tpl.php:28
-msgid "The secret tag \"system:imported\" allows you to find imported bookmarks."
-msgstr "Le tag secret \"system:imported\" vous permet de trouver les signets importés."
+msgid ""
+"The secret tag \"system:imported\" allows you to find imported bookmarks."
+msgstr ""
+"Le tag secret \"system:imported\" vous permet de trouver les signets "
+"importés."
#: data/templates/admin.tpl.php:5
msgid "Users management"
@@ -128,23 +153,18 @@ msgstr "Gestion des utilisateurs"
msgid "Public/Shared/Private"
msgstr "Publique/Partagé/Privé"
-#: data/templates/admin.tpl.php:14
-#: data/templates/bookmarks.tpl.php:93
+#: data/templates/admin.tpl.php:14 data/templates/bookmarks.tpl.php:93
msgid "bookmark(s)"
msgstr "signet(s)"
-#: data/templates/admin.tpl.php:19
-#: data/templates/tag2tagadd.tpl.php:21
+#: data/templates/admin.tpl.php:19 data/templates/tag2tagadd.tpl.php:21
#: data/templates/tag2tagdelete.tpl.php:13
-#: data/templates/tag2tagedit.tpl.php:14
-#: data/templates/tag2tagedit.tpl.php:35
-#: data/templates/tagdelete.tpl.php:6
-#: www/jsScuttle.php:23
+#: data/templates/tag2tagedit.tpl.php:14 data/templates/tag2tagedit.tpl.php:35
+#: data/templates/tagdelete.tpl.php:6 www/jsScuttle.php:23
msgid "Are you sure?"
msgstr "Etes-vous sûr ?"
-#: data/templates/admin.tpl.php:19
-#: data/templates/bookmarks.tpl.php:251
+#: data/templates/admin.tpl.php:19 data/templates/bookmarks.tpl.php:267
msgid "Delete"
msgstr "Supprimer"
@@ -157,19 +177,21 @@ msgid "Check all URLs (May take some time)"
msgstr "Vérifier toutes les URLs (Peut prendre du temps)"
#: data/templates/bookmarkcommondescriptionedit.tpl.php:16
-msgid "Collaborative description: these fields can be viewed and modified by every users"
-msgstr "Description collaborative : ces champs peuvent être vus et modifiés par tous les utilisateurs."
+msgid ""
+"Collaborative description: these fields can be viewed and modified by every "
+"users"
+msgstr ""
+"Description collaborative : ces champs peuvent être vus et modifiés par tous "
+"les utilisateurs."
#: data/templates/bookmarkcommondescriptionedit.tpl.php:18
-#: data/templates/bookmarks.tpl.php:137
-#: data/templates/editbookmark.tpl.php:38
+#: data/templates/bookmarks.tpl.php:137 data/templates/editbookmark.tpl.php:43
msgid "Title"
msgstr "Titre"
#: data/templates/bookmarkcommondescriptionedit.tpl.php:23
-#: data/templates/editbookmark.tpl.php:44
-#: data/templates/editprofile.tpl.php:47
-#: data/templates/profile.tpl.php:33
+#: data/templates/editbookmark.tpl.php:49
+#: data/templates/editprofile.tpl.php:47 data/templates/profile.tpl.php:33
#: data/templates/tagcommondescriptionedit.tpl.php:13
#: data/templates/tagedit.tpl.php:12
msgid "Description"
@@ -187,12 +209,10 @@ msgid "Update"
msgstr "Mettre à jour"
#: data/templates/bookmarkcommondescriptionedit.tpl.php:43
-#: data/templates/editbookmark.tpl.php:98
-#: data/templates/tag2tagadd.tpl.php:24
-#: data/templates/tag2tagedit.tpl.php:38
+#: data/templates/editbookmark.tpl.php:103
+#: data/templates/tag2tagadd.tpl.php:24 data/templates/tag2tagedit.tpl.php:38
#: data/templates/tagcommondescriptionedit.tpl.php:33
-#: data/templates/tagedit.tpl.php:19
-#: data/templates/tagrename.tpl.php:25
+#: data/templates/tagedit.tpl.php:19 data/templates/tagrename.tpl.php:25
msgid "Cancel"
msgstr "Annuler"
@@ -215,23 +235,19 @@ msgstr "Vote contre"
msgid "Bookmarks on this page are managed by an admin user."
msgstr "Les signets de cette page sont gérés par un administrateur."
-#: data/templates/bookmarks.tpl.php:51
-#: data/templates/bookmarks.tpl.php:52
+#: data/templates/bookmarks.tpl.php:51 data/templates/bookmarks.tpl.php:52
msgid "Edit the common description of this tag"
msgstr "Editer la description commune de ce tag"
-#: data/templates/bookmarks.tpl.php:55
-#: data/templates/bookmarks.tpl.php:56
+#: data/templates/bookmarks.tpl.php:55 data/templates/bookmarks.tpl.php:56
msgid "Edit the common description of this bookmark"
msgstr "Editer la description commune de ce signet"
-#: data/templates/bookmarks.tpl.php:76
-#: data/templates/bookmarks.tpl.php:77
+#: data/templates/bookmarks.tpl.php:76 data/templates/bookmarks.tpl.php:77
msgid "Edit your personal description of this tag"
msgstr "Editer votre description personnelle de ce tag"
-#: data/templates/bookmarks.tpl.php:93
-#: data/templates/tags.tpl.php:10
+#: data/templates/bookmarks.tpl.php:93 data/templates/tags.tpl.php:10
#: data/templates/users.tpl.php:8
msgid "Sort by:"
msgstr "Classer par :"
@@ -252,23 +268,19 @@ msgstr "Signets des autres utilisateurs pour ce tag"
msgid "Only your bookmarks for this tag"
msgstr "Uniquement vos signets pour ce tag"
-#: data/templates/bookmarks.tpl.php:177
-#: data/templates/bookmarks.tpl.php:183
+#: data/templates/bookmarks.tpl.php:177 data/templates/bookmarks.tpl.php:183
msgid "First"
msgstr "Première"
-#: data/templates/bookmarks.tpl.php:178
-#: data/templates/bookmarks.tpl.php:184
+#: data/templates/bookmarks.tpl.php:178 data/templates/bookmarks.tpl.php:184
msgid "Previous"
msgstr "Précédent"
-#: data/templates/bookmarks.tpl.php:191
-#: data/templates/bookmarks.tpl.php:194
+#: data/templates/bookmarks.tpl.php:191 data/templates/bookmarks.tpl.php:194
msgid "Next"
msgstr "Suivant"
-#: data/templates/bookmarks.tpl.php:192
-#: data/templates/bookmarks.tpl.php:195
+#: data/templates/bookmarks.tpl.php:192 data/templates/bookmarks.tpl.php:195
msgid "Last"
msgstr "Dernière"
@@ -277,69 +289,66 @@ msgstr "Dernière"
msgid "Page %d of %d"
msgstr "Page %d de %d"
-#: data/templates/bookmarks.tpl.php:245
+#: data/templates/bookmarks.tpl.php:261
msgid "Tags:"
msgstr "Tags:"
-#: data/templates/bookmarks.tpl.php:251
+#: data/templates/bookmarks.tpl.php:267
msgid "Edit"
msgstr "Editer"
-#: data/templates/bookmarks.tpl.php:255
+#: data/templates/bookmarks.tpl.php:271
msgid "Last update"
msgstr "Date de dernière mise à jour"
-#: data/templates/bookmarks.tpl.php:258
+#: data/templates/bookmarks.tpl.php:274
msgid "by"
msgstr "par"
-#: data/templates/bookmarks.tpl.php:260
+#: data/templates/bookmarks.tpl.php:276
msgid "you"
msgstr "vous"
-#: data/templates/bookmarks.tpl.php:274
+#: data/templates/bookmarks.tpl.php:290
#, php-format
msgid " and %s1 other%s"
msgstr " et %s1 autre%s"
-#: data/templates/bookmarks.tpl.php:277
+#: data/templates/bookmarks.tpl.php:293
#, php-format
msgid " and %2$s%1$s others%3$s"
msgstr " et %2$s%1$s autres%3$s"
-#: data/templates/bookmarks.tpl.php:288
+#: data/templates/bookmarks.tpl.php:304
msgid "Copy this bookmark to YOUR bookmarks."
msgstr "Copier ce signet dans VOS signets."
-#: data/templates/bookmarks.tpl.php:289
+#: data/templates/bookmarks.tpl.php:305
msgid "Copy"
msgstr "Copier"
-#: data/templates/bookmarks.tpl.php:309
+#: data/templates/bookmarks.tpl.php:325
msgid "This bookmark is certified by an admin user."
msgstr "Ce signet est certifié par un administrateur."
-#: data/templates/bookmarks.tpl.php:351
+#: data/templates/bookmarks.tpl.php:371
msgid "Private Note on this bookmark"
msgstr "Note privée sur ce signet"
-#: data/templates/bookmarks.tpl.php:363
+#: data/templates/bookmarks.tpl.php:383
msgid "Come back to the top of this page."
msgstr "Revenir en haut de cette page."
-#: data/templates/bookmarks.tpl.php:363
+#: data/templates/bookmarks.tpl.php:383
msgid "Top of the page"
msgstr "Haut de page"
-#: data/templates/bookmarks.tpl.php:369
+#: data/templates/bookmarks.tpl.php:389
msgid "No bookmarks available"
msgstr "Pas de signets disponibles."
-#: data/templates/bottom.inc.php:5
-#: data/templates/toolbar.inc.php:15
-#: data/templates/toolbar.inc.php:28
-#: www/about.php:23
-#: www/about.php:24
+#: data/templates/bottom.inc.php:5 data/templates/toolbar.inc.php:15
+#: data/templates/toolbar.inc.php:28 www/about.php:23 www/about.php:24
msgid "About"
msgstr "À propos"
@@ -350,8 +359,7 @@ msgstr "Propulsé par "
#: data/templates/dynamictags.inc.php:47
#: data/templates/sidebar.block.common.php:19
#: data/templates/sidebar.block.popular.php:34
-#: data/templates/sidebar.block.recent.php:29
-#: data/templates/tags.tpl.php:19
+#: data/templates/sidebar.block.recent.php:29 data/templates/tags.tpl.php:19
msgid "bookmark"
msgid_plural "bookmarks"
msgstr[0] "signet"
@@ -362,8 +370,7 @@ msgstr[1] "Signets"
#: data/templates/sidebar.block.menu.php:74
#: data/templates/sidebar.block.popular.php:23
#: data/templates/sidebar.block.recent.php:34
-#: data/templates/toolbar.inc.php:27
-#: www/populartags.php:46
+#: data/templates/toolbar.inc.php:27 www/populartags.php:46
msgid "Popular Tags"
msgstr "Tags populaires"
@@ -371,131 +378,143 @@ msgstr "Tags populaires"
msgid "Popular Tags From All Users"
msgstr "Tags populaires pour tous les utilisateurs"
-#: data/templates/editbookmark.tpl.php:33
+#: data/templates/editbookmark.tpl.php:38
msgid "Address"
msgstr "Adresse"
-#: data/templates/editbookmark.tpl.php:35
#: data/templates/editbookmark.tpl.php:40
-#: data/templates/editprofile.tpl.php:31
-#: data/templates/tagrename.tpl.php:14
+#: data/templates/editbookmark.tpl.php:45
+#: data/templates/editprofile.tpl.php:31 data/templates/tagrename.tpl.php:14
#: data/templates/tagrename.tpl.php:19
msgid "Required"
msgstr "Requis"
-#: data/templates/editbookmark.tpl.php:45
+#: data/templates/editbookmark.tpl.php:50
msgid "Add Note"
msgstr "Ajouter une note"
-#: data/templates/editbookmark.tpl.php:48
-msgid "You can use anchors to delimite attributes. for example: [publisher]blah[/publisher] "
-msgstr "Vous pouvez utiliser des balises pour délimiter des attributs. Par exemple : [publisher]blah[/publisher]"
+#: data/templates/editbookmark.tpl.php:53
+msgid ""
+"You can use anchors to delimite attributes. for example: [publisher]blah[/"
+"publisher] "
+msgstr ""
+"Vous pouvez utiliser des balises pour délimiter des attributs. Par exemple : "
+"[publisher]blah[/publisher]"
-#: data/templates/editbookmark.tpl.php:51
+#: data/templates/editbookmark.tpl.php:56
msgid "Suggested anchors: "
msgstr "Balises suggérées : "
-#: data/templates/editbookmark.tpl.php:63
+#: data/templates/editbookmark.tpl.php:68
msgid "Private Note"
msgstr "Note privée"
-#: data/templates/editbookmark.tpl.php:65
+#: data/templates/editbookmark.tpl.php:70
msgid "Just visible by you and your contacts."
msgstr "Visible uniquement par vous et vos contacts."
-#: data/templates/editbookmark.tpl.php:69
-#: data/templates/toolbar.inc.php:10
-#: www/tags.php:45
-#: www/tags.php:67
+#: data/templates/editbookmark.tpl.php:74 data/templates/toolbar.inc.php:10
+#: www/tags.php:45 www/tags.php:67
msgid "Tags"
msgstr "Tags"
-#: data/templates/editbookmark.tpl.php:73
+#: data/templates/editbookmark.tpl.php:78
msgid "Comma-separated"
msgstr "Séparés par des virgules"
-#: data/templates/editbookmark.tpl.php:77
-#: data/templates/tag2tagadd.tpl.php:9
-msgid "Note: use \">\" to include one tag in another. e.g.: europe>france>paris"
-msgstr "Note: utiliser \">\" pour inclure un tag dans un autre. ex: europe>france>paris"
+#: data/templates/editbookmark.tpl.php:82 data/templates/tag2tagadd.tpl.php:9
+msgid ""
+"Note: use \">\" to include one tag in another. e.g.: europe>france>paris"
+msgstr ""
+"Note: utiliser \">\" pour inclure un tag dans un autre. ex: "
+"europe>france>paris"
-#: data/templates/editbookmark.tpl.php:81
-#: data/templates/tag2tagadd.tpl.php:8
+#: data/templates/editbookmark.tpl.php:86 data/templates/tag2tagadd.tpl.php:8
msgid "Note: use \"=\" to make synonym two tags. e.g.: france=frenchcountry"
msgstr "Note : utiliser \"=\" pour rendre deux tags synonymes ex: europe=eu"
-#: data/templates/editbookmark.tpl.php:84
+#: data/templates/editbookmark.tpl.php:89
#: data/templates/importDelicious.tpl.php:15
#: data/templates/importNetscape.tpl.php:16
msgid "Privacy"
msgstr "Accès"
-#: data/templates/editbookmark.tpl.php:87
+#: data/templates/editbookmark.tpl.php:92
#: data/templates/importDelicious.tpl.php:18
#: data/templates/importNetscape.tpl.php:19
msgid "Public"
msgstr "Publique"
-#: data/templates/editbookmark.tpl.php:88
+#: data/templates/editbookmark.tpl.php:93
msgid "Shared with Watch List"
msgstr "Partagé avec mes contacts"
-#: data/templates/editbookmark.tpl.php:89
+#: data/templates/editbookmark.tpl.php:94
#: data/templates/importDelicious.tpl.php:20
#: data/templates/importNetscape.tpl.php:21
msgid "Private"
msgstr "Privée"
-#: data/templates/editbookmark.tpl.php:102
+#: data/templates/editbookmark.tpl.php:107
msgid "Delete Bookmark"
msgstr "Supprimer le signet"
-#: data/templates/editbookmark.tpl.php:107
+#: data/templates/editbookmark.tpl.php:112
msgid "edit common description"
msgstr "éditer la description commune"
-#: data/templates/editbookmark.tpl.php:134
+#: data/templates/editbookmark.tpl.php:139
msgid "Bookmarklet"
msgstr "Bookmarklet"
-#: data/templates/editbookmark.tpl.php:140
+#: data/templates/editbookmark.tpl.php:145
#, php-format
-msgid "Click one of the following bookmarklets to add a button you can click whenever you want to add the page you are on to %s"
-msgstr "Déplacez l'un des 'bookmarklet' suivants dans les marques-pages de votre navigateur et cliquez dessus chaque fois que vous souhaitez ajouter un signet pour la page courante dans %s "
+msgid ""
+"Click one of the following bookmarklets to add a button you can click "
+"whenever you want to add the page you are on to %s"
+msgstr ""
+"Déplacez l'un des 'bookmarklet' suivants dans les marques-pages de votre "
+"navigateur et cliquez dessus chaque fois que vous souhaitez ajouter un "
+"signet pour la page courante dans %s "
-#: data/templates/editbookmark.tpl.php:144
+#: data/templates/editbookmark.tpl.php:149
#, php-format
-msgid "Drag one of the following bookmarklets to your browser's bookmarks and click it whenever you want to add the page you are on to %s"
-msgstr "Déplacez l'un des 'bookmarklet' suivants dans les marques-pages de votre navigateur et cliquez dessus chaque fois que vous souhaitez ajouter un signet pour la page courante dans %s "
+msgid ""
+"Drag one of the following bookmarklets to your browser's bookmarks and click "
+"it whenever you want to add the page you are on to %s"
+msgstr ""
+"Déplacez l'un des 'bookmarklet' suivants dans les marques-pages de votre "
+"navigateur et cliquez dessus chaque fois que vous souhaitez ajouter un "
+"signet pour la page courante dans %s "
-#: data/templates/editbookmark.tpl.php:157
#: data/templates/editbookmark.tpl.php:162
+#: data/templates/editbookmark.tpl.php:167
#, php-format
msgid "Post to %s"
msgstr "Ajouter à %s"
-#: data/templates/editbookmark.tpl.php:158
#: data/templates/editbookmark.tpl.php:163
+#: data/templates/editbookmark.tpl.php:168
#, php-format
msgid "Post to %s (Pop-up)"
msgstr "Ajouter à %s (Pop-up)"
-#: data/templates/editbookmark.tpl.php:168
+#: data/templates/editbookmark.tpl.php:173
#: data/templates/importDelicious.tpl.php:26
#: data/templates/importNetscape.tpl.php:27
#: data/templates/importStructure.tpl.php:16
msgid "Import"
msgstr "Importer"
-#: data/templates/editbookmark.tpl.php:170
+#: data/templates/editbookmark.tpl.php:175
msgid "Import bookmarks from bookmark file"
msgstr "Importer les signets depuis un fichier"
-#: data/templates/editbookmark.tpl.php:170
+#: data/templates/editbookmark.tpl.php:175
msgid "Internet Explorer, Mozilla Firefox and Netscape"
msgstr "Internet Explorer, Mozilla Firefox et Netscape"
-#: data/templates/editbookmark.tpl.php:171
+#: data/templates/editbookmark.tpl.php:176
msgid "Import bookmarks from del.icio.us"
msgstr "Importer les signets depuis del.icio.us"
@@ -503,10 +522,8 @@ msgstr "Importer les signets depuis del.icio.us"
msgid "Account Details"
msgstr "Détail du compte"
-#: data/templates/editprofile.tpl.php:14
-#: data/templates/login.tpl.php:21
-#: data/templates/password.tpl.php:10
-#: data/templates/profile.tpl.php:6
+#: data/templates/editprofile.tpl.php:14 data/templates/login.tpl.php:21
+#: data/templates/password.tpl.php:10 data/templates/profile.tpl.php:6
#: data/templates/register.tpl.php:16
msgid "Username"
msgstr "Nom d'utilisateur"
@@ -519,8 +536,7 @@ msgstr "Nouveau mot de passe"
msgid "Confirm Password"
msgstr "Confirmer le mot de passe"
-#: data/templates/editprofile.tpl.php:29
-#: data/templates/password.tpl.php:14
+#: data/templates/editprofile.tpl.php:29 data/templates/password.tpl.php:14
#: data/templates/register.tpl.php:26
msgid "E-mail"
msgstr "E-mail"
@@ -529,18 +545,15 @@ msgstr "E-mail"
msgid "Personal Details"
msgstr "Détails personnels"
-#: data/templates/editprofile.tpl.php:39
-#: data/templates/profile.tpl.php:17
+#: data/templates/editprofile.tpl.php:39 data/templates/profile.tpl.php:17
msgid "Name"
msgstr "Nom"
-#: data/templates/editprofile.tpl.php:43
-#: data/templates/profile.tpl.php:23
+#: data/templates/editprofile.tpl.php:43 data/templates/profile.tpl.php:23
msgid "Homepage"
msgstr "Page personnelle"
-#: data/templates/editprofile.tpl.php:52
-#: www/edit.php:113
+#: data/templates/editprofile.tpl.php:52 www/edit.php:113
msgid "Save Changes"
msgstr "Enregistrer les modifications"
@@ -594,16 +607,28 @@ msgid "Instructions"
msgstr "Instructions"
#: data/templates/importDelicious.tpl.php:33
-msgid "Log in to the <a href=\"http://del.icio.us/api/posts/all\">export page at del.icio.us</a>"
-msgstr "Se connecter à la <a href=\"http://del.icio.us/api/posts/all\">page d'export de del.icio.us</a>"
+msgid ""
+"Log in to the <a href=\"http://del.icio.us/api/posts/all\">export page at "
+"del.icio.us</a>"
+msgstr ""
+"Se connecter à la <a href=\"http://del.icio.us/api/posts/all\">page d'export "
+"de del.icio.us</a>"
#: data/templates/importDelicious.tpl.php:34
-msgid "Save the resulting <abbr title=\"Extensible Markup Language\">XML</abbr> file to your computer"
-msgstr "Enregistrer le fichier <abbr title=\"Extensible Markup Language\">XML</abbr> résultant sur votre ordinateur"
+msgid ""
+"Save the resulting <abbr title=\"Extensible Markup Language\">XML</abbr> "
+"file to your computer"
+msgstr ""
+"Enregistrer le fichier <abbr title=\"Extensible Markup Language\">XML</abbr> "
+"résultant sur votre ordinateur"
#: data/templates/importDelicious.tpl.php:35
-msgid "Click <kbd>Browse...</kbd> to find this file on your computer. The maximum size the file can be is 1MB"
-msgstr "Cliquez sur <kbd>Parcourir...</kbd> pour trouver le fichier sur votre ordinateur. La taille maximale du fichier ne peut excèder 1Mo"
+msgid ""
+"Click <kbd>Browse...</kbd> to find this file on your computer. The maximum "
+"size the file can be is 1MB"
+msgstr ""
+"Cliquez sur <kbd>Parcourir...</kbd> pour trouver le fichier sur votre "
+"ordinateur. La taille maximale du fichier ne peut excèder 1Mo"
#: data/templates/importDelicious.tpl.php:36
#: data/templates/importNetscape.tpl.php:43
@@ -612,43 +637,62 @@ msgstr "Selectionnez la vision par défaut à appliquer à vos signets importés
#: data/templates/importDelicious.tpl.php:37
#: data/templates/importNetscape.tpl.php:44
-msgid "Click <kbd>Import</kbd> to start importing the bookmarks; it may take a minute"
-msgstr "Cliquez sur <kbd>Importer</kbd> pour débuter l'import des signets; cette opération peut prendre quelques minutes"
+msgid ""
+"Click <kbd>Import</kbd> to start importing the bookmarks; it may take a "
+"minute"
+msgstr ""
+"Cliquez sur <kbd>Importer</kbd> pour débuter l'import des signets; cette "
+"opération peut prendre quelques minutes"
#: data/templates/importNetscape.tpl.php:35
msgid "Export your bookmarks from your browser to a file"
msgstr "Exporter vos signets dans un fichier depuis votre navigateur"
#: data/templates/importNetscape.tpl.php:37
-msgid "Internet Explorer: <kbd>File &gt; Import and Export... &gt; Export Favorites"
-msgstr "Internet Explorer: <kbd>Ficher &gt; Importer et Exporter... &gt; Exporter les favoris"
+msgid ""
+"Internet Explorer: <kbd>File &gt; Import and Export... &gt; Export Favorites"
+msgstr ""
+"Internet Explorer: <kbd>Ficher &gt; Importer et Exporter... &gt; Exporter "
+"les favoris"
#: data/templates/importNetscape.tpl.php:38
-msgid "Mozilla Firefox: <kbd>Bookmarks &gt; Manage Bookmarks... &gt; File &gt; Export..."
-msgstr "Mozilla Firefox: <kbd>Marques-pages &gt; Gérer les marques-pages... &gt; Fichier &gt; Exporter..."
+msgid ""
+"Mozilla Firefox: <kbd>Bookmarks &gt; Manage Bookmarks... &gt; File &gt; "
+"Export..."
+msgstr ""
+"Mozilla Firefox: <kbd>Marques-pages &gt; Gérer les marques-pages... &gt; "
+"Fichier &gt; Exporter..."
#: data/templates/importNetscape.tpl.php:39
-msgid "Netscape: <kbd>Bookmarks &gt; Manage Bookmarks... &gt; Tools &gt; Export..."
-msgstr "Netscape: <kbd>Marques-pages &gt; Gérer les marques-pages... &gt; Outils &gt; Exporter..."
+msgid ""
+"Netscape: <kbd>Bookmarks &gt; Manage Bookmarks... &gt; Tools &gt; Export..."
+msgstr ""
+"Netscape: <kbd>Marques-pages &gt; Gérer les marques-pages... &gt; Outils "
+"&gt; Exporter..."
#: data/templates/importNetscape.tpl.php:42
-msgid "Click <kbd>Browse...</kbd> to find the saved bookmark file on your computer. The maximum size the file can be is 1MB"
-msgstr "Cliquez sur <kbd>Parcourir...</kbd> pour trouver le fichier sur votre ordinateur. La taille maximale du fichier ne peut excèder 1Mo"
+msgid ""
+"Click <kbd>Browse...</kbd> to find the saved bookmark file on your computer. "
+"The maximum size the file can be is 1MB"
+msgstr ""
+"Cliquez sur <kbd>Parcourir...</kbd> pour trouver le fichier sur votre "
+"ordinateur. La taille maximale du fichier ne peut excèder 1Mo"
#: data/templates/importStructure.tpl.php:24
msgid "Create your structure into a simple text file and following this model:"
msgstr ""
#: data/templates/importStructure.tpl.php:35
-msgid "Then import the file. The tags and their relations will be added to your profile."
+msgid ""
+"Then import the file. The tags and their relations will be added to your "
+"profile."
msgstr ""
#: data/templates/login.tpl.php:13
msgid "Please activate cookies"
msgstr "SVP activez les cookies"
-#: data/templates/login.tpl.php:26
-#: data/templates/register.tpl.php:21
+#: data/templates/login.tpl.php:26 data/templates/register.tpl.php:21
msgid "Password"
msgstr "Mot de passe"
@@ -656,8 +700,7 @@ msgstr "Mot de passe"
msgid "Don't ask for my password for 2 weeks"
msgstr "Ne pas demander mon mot de passe pendant 2 semaines"
-#: data/templates/login.tpl.php:32
-#: data/templates/toolbar.inc.php:29
+#: data/templates/login.tpl.php:32 data/templates/toolbar.inc.php:29
#: www/login.php:57
msgid "Log In"
msgstr "Se connecter"
@@ -668,8 +711,14 @@ msgstr "Avez-vous oublié votre mot de passe ?"
#: data/templates/password.tpl.php:5
#, php-format
-msgid "If you have forgotten your password, %s can generate a new one. Enter the username and e-mail address of your account into the form below and we will e-mail your new password to you."
-msgstr "Si vous avez oublié votre mot de passe, %s peut en générer un nouveau. Entrez le nom d'utilisateur et l'adresse email de votre compte dans le formulaire ci-dessous et nous vous enverrons un nouveau mot de passe."
+msgid ""
+"If you have forgotten your password, %s can generate a new one. Enter the "
+"username and e-mail address of your account into the form below and we will "
+"e-mail your new password to you."
+msgstr ""
+"Si vous avez oublié votre mot de passe, %s peut en générer un nouveau. "
+"Entrez le nom d'utilisateur et l'adresse email de votre compte dans le "
+"formulaire ci-dessous et nous vous enverrons un nouveau mot de passe."
#: data/templates/password.tpl.php:19
msgid "Generate Password"
@@ -693,8 +742,7 @@ msgstr "Mes contacts"
msgid "Watched By"
msgstr "Dans les contacts de"
-#: data/templates/profile.tpl.php:68
-#: data/templates/toolbar.inc.php:9
+#: data/templates/profile.tpl.php:68 data/templates/toolbar.inc.php:9
msgid "Bookmarks"
msgstr "Signets"
@@ -704,12 +752,20 @@ msgstr "Aller aux signets"
#: data/templates/register.tpl.php:11
#, php-format
-msgid "Sign up here to create a free %s account. All the information requested below is required"
-msgstr "Enregistrez-vous ici pour créer un compte gratuit %s. Toutes les informations requises ci-dessous sont nécessaires."
+msgid ""
+"Sign up here to create a free %s account. All the information requested "
+"below is required"
+msgstr ""
+"Enregistrez-vous ici pour créer un compte gratuit %s. Toutes les "
+"informations requises ci-dessous sont nécessaires."
#: data/templates/register.tpl.php:18
-msgid " at least 5 characters, alphanumeric (no spaces, no dots or other special ones)"
-msgstr " au moins 5 caractères, alphanumériques (pas d'espaces, pas de points ou autre caractère spécial)"
+msgid ""
+" at least 5 characters, alphanumeric (no spaces, no dots or other special "
+"ones)"
+msgstr ""
+" au moins 5 caractères, alphanumériques (pas d'espaces, pas de points ou "
+"autre caractère spécial)"
#: data/templates/register.tpl.php:28
msgid " to send you your password if you forget it"
@@ -719,8 +775,7 @@ msgstr " pour vous envoyer votre mot de passe en cas de perte"
msgid "Antispam question"
msgstr "Question antispam"
-#: data/templates/register.tpl.php:41
-#: data/templates/toolbar.inc.php:31
+#: data/templates/register.tpl.php:41 data/templates/toolbar.inc.php:31
#: www/register.php:83
msgid "Register"
msgstr "S'enregistrer"
@@ -802,7 +857,8 @@ msgstr "Tags Principaux"
#: data/templates/sidebar.block.menu2.php:29
msgid "This menu is composed of keywords (tags) organized by admins."
-msgstr "Ce menu est composé de mots-clefs (tags) organisés par les administrateurs."
+msgstr ""
+"Ce menu est composé de mots-clefs (tags) organisés par les administrateurs."
#: data/templates/sidebar.block.recent.php:18
msgid "Recent Tags"
@@ -820,25 +876,22 @@ msgstr "Dernières recherches"
msgid "Number of bookmarks for this query"
msgstr "Nombre de signets pour cette recherche"
-#: data/templates/sidebar.block.tagactions.php:9
-#: www/tagrename.php:72
+#: data/templates/sidebar.block.tagactions.php:9 www/tagrename.php:72
msgid "Rename Tag"
msgid_plural "Rename Tags"
msgstr[0] "Renommer le tag"
msgstr[1] "Renommer les tags"
-#: data/templates/sidebar.block.tagactions.php:22
-#: www/tagdelete.php:54
+#: data/templates/sidebar.block.tagactions.php:22 www/tagdelete.php:54
msgid "Delete Tag"
msgstr "Supprimer le tag"
-#: data/templates/sidebar.block.tagactions.php:24
-#: www/tagedit.php:61
+#: data/templates/sidebar.block.tagactions.php:24 www/tagedit.php:61
msgid "Edit Tag Description"
msgstr "Editer la description du tag"
#: data/templates/sidebar.block.tagactions.php:26
-#: www/tagcommondescriptionedit.php:64
+#: www/tagcommondescriptionedit.php:76
msgid "Edit Tag Common Description"
msgstr "Editer la description commune du tag"
@@ -850,8 +903,7 @@ msgstr "Créer un lien vers un autre tag"
msgid "New Users"
msgstr "Nouveaux Utilisateurs"
-#: data/templates/sidebar.block.users.php:23
-#: data/templates/users.tpl.php:17
+#: data/templates/sidebar.block.users.php:23 data/templates/users.tpl.php:17
msgid "bookmarks"
msgstr "signets"
@@ -905,11 +957,14 @@ msgstr "Créer un nouveau lien"
#: data/templates/tag2tagadd.tpl.php:19
#, php-format
-msgid "Note: include a tag into '%s' tag (e.g. %s>countries) display the tag into the menu box"
-msgstr "Note : inclure un tag dans le tag '%s' (e.g. %s>countries) affiche ce tag dans la boîte de menu"
+msgid ""
+"Note: include a tag into '%s' tag (e.g. %s>countries) display the tag into "
+"the menu box"
+msgstr ""
+"Note : inclure un tag dans le tag '%s' (e.g. %s>countries) affiche ce tag "
+"dans la boîte de menu"
-#: data/templates/tag2tagadd.tpl.php:23
-#: data/templates/tag2tagedit.tpl.php:37
+#: data/templates/tag2tagadd.tpl.php:23 data/templates/tag2tagedit.tpl.php:37
msgid "Create"
msgstr "Créer"
@@ -926,15 +981,13 @@ msgid "No links"
msgstr "Pas de liens"
#: data/templates/tag2tagdelete.tpl.php:15
-#: data/templates/tag2tagedit.tpl.php:16
-#: data/templates/tagdelete.tpl.php:8
+#: data/templates/tag2tagedit.tpl.php:16 data/templates/tagdelete.tpl.php:8
#: www/jsScuttle.php:23
msgid "Yes"
msgstr "Oui"
#: data/templates/tag2tagdelete.tpl.php:16
-#: data/templates/tag2tagedit.tpl.php:17
-#: data/templates/tagdelete.tpl.php:9
+#: data/templates/tag2tagedit.tpl.php:17 data/templates/tagdelete.tpl.php:9
#: www/jsScuttle.php:23
msgid "No"
msgstr "Non"
@@ -959,33 +1012,27 @@ msgstr "Nouveau"
msgid "Rename"
msgstr "Renommer"
-#: data/templates/tags.tpl.php:11
-#: data/templates/users.tpl.php:9
+#: data/templates/tags.tpl.php:11 data/templates/users.tpl.php:9
msgid "Alphabet"
msgstr "Alphabet"
-#: data/templates/tags.tpl.php:12
-#: data/templates/users.tpl.php:10
+#: data/templates/tags.tpl.php:12 data/templates/users.tpl.php:10
msgid "Popularity"
msgstr "Popularité"
-#: data/templates/toolbar.inc.php:8
-#: data/templates/toolbar.inc.php:26
+#: data/templates/toolbar.inc.php:8 data/templates/toolbar.inc.php:26
msgid "Home"
msgstr "Accueil"
-#: data/templates/toolbar.inc.php:11
-#: www/watchlist.php:106
+#: data/templates/toolbar.inc.php:11 www/watchlist.php:106
msgid "Watchlist"
msgstr "Contacts"
-#: data/templates/toolbar.inc.php:12
-#: www/profile.php:67
+#: data/templates/toolbar.inc.php:12 www/profile.php:67
msgid "Profile"
msgstr "Profil"
-#: data/templates/toolbar.inc.php:13
-#: www/bookmarks.php:209
+#: data/templates/toolbar.inc.php:13 www/bookmarks.php:209
msgid "Add a Bookmark"
msgstr "Ajouter un signet"
@@ -998,8 +1045,14 @@ msgid "Admin"
msgstr "Admin"
#: data/templates/top.inc.php:49
-msgid "Admins, your installation is in \"Debug Mode\" ($debugMode = true). To go in \"Normal Mode\" and hide debugging messages, change $debugMode to false into config.php."
-msgstr "Admins, votre installation est en \"Mode Debug\" ($debugMode = true). Pour passer en \"Mode Normal\" et cacher les messages de debuggage, changez $debugMode à false dans config.inc.php."
+msgid ""
+"Admins, your installation is in \"Debug Mode\" ($debugMode = true). To go in "
+"\"Normal Mode\" and hide debugging messages, change $debugMode to false into "
+"config.php."
+msgstr ""
+"Admins, votre installation est en \"Mode Debug\" ($debugMode = true). Pour "
+"passer en \"Mode Normal\" et cacher les messages de debuggage, changez "
+"$debugMode à false dans config.inc.php."
#: data/templates/users.tpl.php:17
msgid "profile"
@@ -1026,33 +1079,24 @@ msgstr "Problème avec "
msgid "You are not allowed to delete this bookmark"
msgstr "Vous n'êtes pas autorisés à supprimer ce signet"
-#: www/ajaxDelete.php:41
-#: www/edit.php:103
+#: www/ajaxDelete.php:41 www/edit.php:103
msgid "Failed to delete bookmark"
msgstr "Erreur dans la suppression du signet"
-#: www/alltags.php:49
+#: www/alltags.php:50
msgid "All Tags"
msgstr "Tous les tags"
-#: www/alltags.php:55
-#: www/bookmarks.php:96
-#: www/populartags.php:52
-#: www/profile.php:51
-#: www/rss.php:67
-#: www/search.php:109
-#: www/watch.php:45
+#: www/alltags.php:56 www/bookmarks.php:96 www/populartags.php:52
+#: www/profile.php:51 www/rss.php:76 www/search.php:109 www/watch.php:45
#: www/watchlist.php:61
#, php-format
msgid "User with username %s was not found"
msgstr "L'utilisateur %s n'a pas été trouvé."
-#: www/bookmarkcommondescriptionedit.php:51
-#: www/tag2tagadd.php:37
-#: www/tag2tagdelete.php:41
-#: www/tag2tagedit.php:33
-#: www/tagcommondescriptionedit.php:43
-#: www/tagedit.php:43
+#: www/bookmarkcommondescriptionedit.php:51 www/tag2tagadd.php:37
+#: www/tag2tagdelete.php:41 www/tag2tagedit.php:33
+#: www/tagcommondescriptionedit.php:51 www/tagedit.php:43
msgid "Permission denied."
msgstr "Permission non accordée."
@@ -1068,19 +1112,15 @@ msgstr "Erreur dans la mise à jour de la description du signet"
msgid "Edit Bookmark Common Description"
msgstr "Editer la description commune du signet"
-#: www/bookmarks.php:111
-#: www/tags.php:47
+#: www/bookmarks.php:111 www/tags.php:47
msgid "Remove the tag from the selection"
msgstr "Retirer le tag de la sélection"
-#: www/bookmarks.php:131
-#: www/edit.php:65
+#: www/bookmarks.php:131 www/edit.php:65
msgid "Your bookmark must have a title and an address"
msgstr "Votre signet doit avoir un titre et une adresse."
-#: www/bookmarks.php:152
-#: www/edit.php:83
-#: www/edit.php:86
+#: www/bookmarks.php:152 www/edit.php:83 www/edit.php:86
msgid "Bookmark saved"
msgstr "Signet enregistré."
@@ -1088,11 +1128,13 @@ msgstr "Signet enregistré."
msgid "(Come back to previous page.)"
msgstr "(Revenir à la page précédente.)"
-#: www/bookmarks.php:159
-#: www/import.php:106
-#: www/importNetscape.php:108
-msgid "There was an error saving your bookmark. Please try again or contact the administrator."
-msgstr "Il y a eu une erreur en enregistrant ce signet. Veuillez rééssayer ou contacter votre administrateur."
+#: www/bookmarks.php:159 www/import.php:106 www/importNetscape.php:108
+msgid ""
+"There was an error saving your bookmark. Please try again or contact the "
+"administrator."
+msgstr ""
+"Il y a eu une erreur en enregistrant ce signet. Veuillez rééssayer ou "
+"contacter votre administrateur."
#: www/bookmarks.php:216
msgid "Add Bookmark"
@@ -1102,13 +1144,11 @@ msgstr "Ajouter signet"
msgid "You must be logged in before you can add bookmarks."
msgstr "Vous devez être authentifié avant de pouvoir ajouter des signets."
-#: www/bookmarks.php:274
-#: www/bookmarks.php:275
+#: www/bookmarks.php:274 www/bookmarks.php:275
msgid "My Bookmarks"
msgstr "Mes signets"
-#: www/edit.php:44
-#: www/edit.php:45
+#: www/edit.php:44 www/edit.php:45
msgid "Edit Bookmark"
msgstr "Editer le signet"
@@ -1171,8 +1211,7 @@ msgstr "Signets trouvés :"
msgid "Bookmarks imported: "
msgstr "Signets importés :"
-#: www/importNetscape.php:117
-#: www/importNetscape.php:122
+#: www/importNetscape.php:117 www/importNetscape.php:122
msgid "Import Bookmarks from Browser File"
msgstr "Importer les signets depuis un fichier"
@@ -1197,11 +1236,11 @@ msgstr "Vous êtes maintenant déconnecté."
msgid "%s: Recent bookmarks"
msgstr "%s: Signets récents"
-#: www/index.php:78
+#: www/index.php:75
msgid "Store, share and tag your favourite links"
msgstr "Conservez, partagez et taggez vos liens favoris"
-#: www/index.php:79
+#: www/index.php:76
msgid "All Bookmarks"
msgstr "Tous les signets"
@@ -1215,35 +1254,51 @@ msgstr "Non Disponible"
#: www/login.php:48
msgid "The details you have entered are incorrect. Please try again."
-msgstr "Les informations que vous avez entrées sont incorrectes. Veuillez recommencer."
+msgstr ""
+"Les informations que vous avez entrées sont incorrectes. Veuillez "
+"recommencer."
#: www/password.php:36
msgid "You must enter your username."
msgstr "Vous devez entrer votre nom d'utilisateur."
#: www/password.php:40
-msgid "You must enter your <abbr title=\"electronic mail\">e-mail</abbr> address."
-msgstr "Vous <em>devez</em> saisir une <abbr title=\"adresse électronique\">E-mail</abbr>."
+msgid ""
+"You must enter your <abbr title=\"electronic mail\">e-mail</abbr> address."
+msgstr ""
+"Vous <em>devez</em> saisir une <abbr title=\"adresse électronique\">E-mail</"
+"abbr>."
#: www/password.php:48
msgid "No matches found for that username."
msgstr "Rien de trouvé pour ce nom d'utilisateur."
#: www/password.php:51
-msgid "No matches found for that combination of username and <abbr title=\"electronic mail\">e-mail</abbr> address."
-msgstr "Pas d'entrée pour ce nom d'utilisateur et cet <abbr title=\"adresse mail\">e-mail</abbr>."
+msgid ""
+"No matches found for that combination of username and <abbr title="
+"\"electronic mail\">e-mail</abbr> address."
+msgstr ""
+"Pas d'entrée pour ce nom d'utilisateur et cet <abbr title=\"adresse mail\">e-"
+"mail</abbr>."
#: www/password.php:59
-msgid "There was an error while generating your new password. Please try again."
-msgstr "Il y a eu une erreur en enregistrant ce signet. Veuillez rééssayer ou contacter votre administrateur."
+msgid ""
+"There was an error while generating your new password. Please try again."
+msgstr ""
+"Il y a eu une erreur en enregistrant ce signet. Veuillez rééssayer ou "
+"contacter votre administrateur."
#: www/password.php:63
msgid "Your new password is:"
msgstr "Votre nouveau mot de passe est:"
#: www/password.php:63
-msgid "To keep your bookmarks secure, you should change this password in your profile the next time you log in."
-msgstr "Pour garder vos signets sûrs, vous devriez changer ce mot de passe dans votre profil lors de votre prochaine authentification."
+msgid ""
+"To keep your bookmarks secure, you should change this password in your "
+"profile the next time you log in."
+msgstr ""
+"Pour garder vos signets sûrs, vous devriez changer ce mot de passe dans "
+"votre profil lors de votre prochaine authentification."
#: www/password.php:66
#, php-format
@@ -1259,8 +1314,7 @@ msgstr "Nouveau mot de passe généré et envoyé à l'adresse %s"
msgid "Forgotten Password"
msgstr "Mot de passe oublié"
-#: www/profile.php:59
-#: www/watchlist.php:119
+#: www/profile.php:59 www/watchlist.php:119
msgid "Username was not specified"
msgstr "Le nom d'utilisateur n'a pas été spécifié."
@@ -1286,7 +1340,8 @@ msgstr "Adresse de courrier électronique invalide."
#: www/profile.php:106
msgid "An error occurred while saving your changes."
-msgstr "Une erreur s'est produite pendant l'enregistrement de vos modifications."
+msgstr ""
+"Une erreur s'est produite pendant l'enregistrement de vos modifications."
#: www/profile.php:108
msgid "Changes saved."
@@ -1294,7 +1349,9 @@ msgstr "Modifications enregistrées."
#: www/register.php:46
msgid "You <em>must</em> enter a username, password and e-mail address."
-msgstr "Vous <em>devez</em> saisir un nom d'utilisateur, un mot de passe, un nom et un <abbr title=\"adresse électronique\">e-mail</abbr>"
+msgstr ""
+"Vous <em>devez</em> saisir un nom d'utilisateur, un mot de passe, un nom et "
+"un <abbr title=\"adresse électronique\">e-mail</abbr>"
#: www/register.php:50
msgid "This username has been reserved, please make another choice."
@@ -1305,8 +1362,12 @@ msgid "This username already exists, please make another choice."
msgstr "Ce nom d'utilisateur existe déjà, veuillez en choisir un autre."
#: www/register.php:58
-msgid "This username is not valid (too short, too long, forbidden characters...), please make another choice."
-msgstr "Ce nom d'utilisateur n'est pas valide (trop court, trop long, caractères interdits...), Merci de faire un autre choix."
+msgid ""
+"This username is not valid (too short, too long, forbidden characters...), "
+"please make another choice."
+msgstr ""
+"Ce nom d'utilisateur n'est pas valide (trop court, trop long, caractères "
+"interdits...), Merci de faire un autre choix."
#: www/register.php:62
msgid "E-mail address is not valid. Please try again."
@@ -1324,13 +1385,12 @@ msgstr "Votre inscription a bien été prise en compte !"
msgid "Registration failed. Please try again."
msgstr "Enregistrement raté. Veuillez rééssayer."
-#: www/rss.php:84
+#: www/rss.php:93
#, php-format
msgid "Recent bookmarks posted to %s"
msgstr "Signets ajoutés récemment à %s"
-#: www/search.php:81
-#: www/search.php:145
+#: www/search.php:81 www/search.php:145
msgid "Search Bookmarks"
msgstr "Recherche de signets"
@@ -1370,11 +1430,11 @@ msgstr "Effacer un lien entre tags"
msgid "Edit Link Between Tags"
msgstr "Editer un lien entre tags"
-#: www/tagcommondescriptionedit.php:55
+#: www/tagcommondescriptionedit.php:62
msgid "Tag common description updated"
msgstr "Editer la description commune du tag"
-#: www/tagcommondescriptionedit.php:58
+#: www/tagcommondescriptionedit.php:67
msgid "Failed to update the tag common description"
msgstr "Impossible de mettre à jour la description commune du tag"
@@ -1432,34 +1492,45 @@ msgstr "Conseil pour admin:"
#: www/gsearch/index.php:33
msgid "To refresh manually Google Custom Search Engine, goes to: "
-msgstr "Pour rafraîchir manuellement le moteur de Google Custom Search, allez à :"
+msgstr ""
+"Pour rafraîchir manuellement le moteur de Google Custom Search, allez à :"
#: www/gsearch/index.php:35
-msgid "If no result appears, check that all the urls are valid in the admin section."
-msgstr "Si aucun résultat apparaît, vérifier que toutes les urls sont valides dans la section admin."
+msgid ""
+"If no result appears, check that all the urls are valid in the admin section."
+msgstr ""
+"Si aucun résultat apparaît, vérifier que toutes les urls sont valides dans "
+"la section admin."
#~ msgid "Add this tag to the query"
#~ msgstr "Ajouter ce tag à la requête"
+
#~ msgid "Last Users"
#~ msgstr "Derniers utilisateurs"
#, fuzzy
#~ msgid "Watched by"
#~ msgstr "Consultés"
+
#~ msgid "URL"
#~ msgstr "URL"
+
#~ msgid "for"
#~ msgstr "pour"
+
#~ msgid "Recent Bookmarks"
#~ msgstr "Signets récents"
+
#~ msgid "plus"
#~ msgstr "plus"
+
#~ msgid ""
#~ "<strong><a href=\"register.php\">Register now</a></strong> to start using "
#~ "%s!"
#~ msgstr ""
#~ "<a href=\"register.php\">Enregistrez-vous maintenant</a> pour poster vos "
#~ "propres signets sur %s !"
+
#~ msgid ""
#~ "<a href=\"http://sourceforge.net/projects/semanticscuttle/\">Semantic "
#~ "Scuttle</a> is licensed under the <a href=\"http://www.gnu.org/copyleft/"
@@ -1470,12 +1541,15 @@ msgstr "Si aucun résultat apparaît, vérifier que toutes les urls sont valides
#~ "Scuttle</a>, sous license <a href=\"http://www.gnu.org/copyleft/gpl.html"
#~ "\"><acronym title=\"GNU's Not Unix\">GNU</acronym> General Public "
#~ "License</a> (vous pouvez donc l'héberger sur votre propre serveur)."
+
#~ msgid "edit"
#~ msgstr "éditer"
+
#~ msgid "User with username %s not was not found"
#~ msgstr "L'utilisateur %s n'a pas été trouvé."
+
#~ msgid "%s Bookmarks"
#~ msgstr "Signets de %s"
+
#~ msgid "<abbr title=\"Electronic mail\">E-mail</abbr>"
#~ msgstr "<abbr title=\"Adresse électronique\">E-mail</abbr>"
-
diff --git a/data/locales/messages.po b/data/locales/messages.po
index 1a142a0..2f35f64 100644
--- a/data/locales/messages.po
+++ b/data/locales/messages.po
@@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2009-11-16 20:55+0100\n"
+"POT-Creation-Date: 2010-09-15 19:15+0200\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
@@ -17,50 +17,50 @@ msgstr ""
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\n"
-#: src/SemanticScuttle/functions.php:163
+#: src/SemanticScuttle/functions.php:189
msgid "message_die() was called multiple times."
msgstr ""
-#: src/SemanticScuttle/functions.php:175
+#: src/SemanticScuttle/functions.php:201
msgid "SQL Error"
msgstr ""
-#: src/SemanticScuttle/functions.php:181
+#: src/SemanticScuttle/functions.php:207
msgid "Line"
msgstr ""
-#: src/SemanticScuttle/functions.php:181
+#: src/SemanticScuttle/functions.php:207
#: data/templates/importDelicious.tpl.php:8
#: data/templates/importNetscape.tpl.php:9
#: data/templates/importStructure.tpl.php:10
msgid "File"
msgstr ""
-#: src/SemanticScuttle/functions.php:189
+#: src/SemanticScuttle/functions.php:215
msgid "Information"
msgstr ""
-#: src/SemanticScuttle/functions.php:194
+#: src/SemanticScuttle/functions.php:220
msgid "Critical Information"
msgstr ""
-#: src/SemanticScuttle/functions.php:199
+#: src/SemanticScuttle/functions.php:225
msgid "An error occured"
msgstr ""
-#: src/SemanticScuttle/functions.php:202
+#: src/SemanticScuttle/functions.php:228
msgid "General Error"
msgstr ""
-#: src/SemanticScuttle/functions.php:210
+#: src/SemanticScuttle/functions.php:236
msgid "An critical error occured"
msgstr ""
-#: src/SemanticScuttle/functions.php:213
+#: src/SemanticScuttle/functions.php:239
msgid "Critical Error"
msgstr ""
-#: src/SemanticScuttle/functions.php:222
+#: src/SemanticScuttle/functions.php:248
msgid "DEBUG MODE"
msgstr ""
@@ -150,7 +150,7 @@ msgstr ""
msgid "Are you sure?"
msgstr ""
-#: data/templates/admin.tpl.php:19 data/templates/bookmarks.tpl.php:251
+#: data/templates/admin.tpl.php:19 data/templates/bookmarks.tpl.php:267
msgid "Delete"
msgstr ""
@@ -169,12 +169,12 @@ msgid ""
msgstr ""
#: data/templates/bookmarkcommondescriptionedit.tpl.php:18
-#: data/templates/bookmarks.tpl.php:137 data/templates/editbookmark.tpl.php:38
+#: data/templates/bookmarks.tpl.php:137 data/templates/editbookmark.tpl.php:43
msgid "Title"
msgstr ""
#: data/templates/bookmarkcommondescriptionedit.tpl.php:23
-#: data/templates/editbookmark.tpl.php:44
+#: data/templates/editbookmark.tpl.php:49
#: data/templates/editprofile.tpl.php:47 data/templates/profile.tpl.php:33
#: data/templates/tagcommondescriptionedit.tpl.php:13
#: data/templates/tagedit.tpl.php:12
@@ -193,8 +193,8 @@ msgid "Update"
msgstr ""
#: data/templates/bookmarkcommondescriptionedit.tpl.php:43
-#: data/templates/editbookmark.tpl.php:98 data/templates/tag2tagadd.tpl.php:24
-#: data/templates/tag2tagedit.tpl.php:38
+#: data/templates/editbookmark.tpl.php:103
+#: data/templates/tag2tagadd.tpl.php:24 data/templates/tag2tagedit.tpl.php:38
#: data/templates/tagcommondescriptionedit.tpl.php:33
#: data/templates/tagedit.tpl.php:19 data/templates/tagrename.tpl.php:25
msgid "Cancel"
@@ -273,61 +273,61 @@ msgstr ""
msgid "Page %d of %d"
msgstr ""
-#: data/templates/bookmarks.tpl.php:245
+#: data/templates/bookmarks.tpl.php:261
msgid "Tags:"
msgstr ""
-#: data/templates/bookmarks.tpl.php:251
+#: data/templates/bookmarks.tpl.php:267
msgid "Edit"
msgstr ""
-#: data/templates/bookmarks.tpl.php:255
+#: data/templates/bookmarks.tpl.php:271
msgid "Last update"
msgstr ""
-#: data/templates/bookmarks.tpl.php:258
+#: data/templates/bookmarks.tpl.php:274
msgid "by"
msgstr ""
-#: data/templates/bookmarks.tpl.php:260
+#: data/templates/bookmarks.tpl.php:276
msgid "you"
msgstr ""
-#: data/templates/bookmarks.tpl.php:274
+#: data/templates/bookmarks.tpl.php:290
#, php-format
msgid " and %s1 other%s"
msgstr ""
-#: data/templates/bookmarks.tpl.php:277
+#: data/templates/bookmarks.tpl.php:293
#, php-format
msgid " and %2$s%1$s others%3$s"
msgstr ""
-#: data/templates/bookmarks.tpl.php:288
+#: data/templates/bookmarks.tpl.php:304
msgid "Copy this bookmark to YOUR bookmarks."
msgstr ""
-#: data/templates/bookmarks.tpl.php:289
+#: data/templates/bookmarks.tpl.php:305
msgid "Copy"
msgstr ""
-#: data/templates/bookmarks.tpl.php:309
+#: data/templates/bookmarks.tpl.php:325
msgid "This bookmark is certified by an admin user."
msgstr ""
-#: data/templates/bookmarks.tpl.php:351
+#: data/templates/bookmarks.tpl.php:371
msgid "Private Note on this bookmark"
msgstr ""
-#: data/templates/bookmarks.tpl.php:363
+#: data/templates/bookmarks.tpl.php:383
msgid "Come back to the top of this page."
msgstr ""
-#: data/templates/bookmarks.tpl.php:363
+#: data/templates/bookmarks.tpl.php:383
msgid "Top of the page"
msgstr ""
-#: data/templates/bookmarks.tpl.php:369
+#: data/templates/bookmarks.tpl.php:389
msgid "No bookmarks available"
msgstr ""
@@ -362,133 +362,133 @@ msgstr ""
msgid "Popular Tags From All Users"
msgstr ""
-#: data/templates/editbookmark.tpl.php:33
+#: data/templates/editbookmark.tpl.php:38
msgid "Address"
msgstr ""
-#: data/templates/editbookmark.tpl.php:35
#: data/templates/editbookmark.tpl.php:40
+#: data/templates/editbookmark.tpl.php:45
#: data/templates/editprofile.tpl.php:31 data/templates/tagrename.tpl.php:14
#: data/templates/tagrename.tpl.php:19
msgid "Required"
msgstr ""
-#: data/templates/editbookmark.tpl.php:45
+#: data/templates/editbookmark.tpl.php:50
msgid "Add Note"
msgstr ""
-#: data/templates/editbookmark.tpl.php:48
+#: data/templates/editbookmark.tpl.php:53
msgid ""
"You can use anchors to delimite attributes. for example: [publisher]blah[/"
"publisher] "
msgstr ""
-#: data/templates/editbookmark.tpl.php:51
+#: data/templates/editbookmark.tpl.php:56
msgid "Suggested anchors: "
msgstr ""
-#: data/templates/editbookmark.tpl.php:63
+#: data/templates/editbookmark.tpl.php:68
msgid "Private Note"
msgstr ""
-#: data/templates/editbookmark.tpl.php:65
+#: data/templates/editbookmark.tpl.php:70
msgid "Just visible by you and your contacts."
msgstr ""
-#: data/templates/editbookmark.tpl.php:69 data/templates/toolbar.inc.php:10
+#: data/templates/editbookmark.tpl.php:74 data/templates/toolbar.inc.php:10
#: www/tags.php:45 www/tags.php:67
msgid "Tags"
msgstr ""
-#: data/templates/editbookmark.tpl.php:73
+#: data/templates/editbookmark.tpl.php:78
msgid "Comma-separated"
msgstr ""
-#: data/templates/editbookmark.tpl.php:77 data/templates/tag2tagadd.tpl.php:9
+#: data/templates/editbookmark.tpl.php:82 data/templates/tag2tagadd.tpl.php:9
msgid ""
"Note: use \">\" to include one tag in another. e.g.: europe>france>paris"
msgstr ""
-#: data/templates/editbookmark.tpl.php:81 data/templates/tag2tagadd.tpl.php:8
+#: data/templates/editbookmark.tpl.php:86 data/templates/tag2tagadd.tpl.php:8
msgid "Note: use \"=\" to make synonym two tags. e.g.: france=frenchcountry"
msgstr ""
-#: data/templates/editbookmark.tpl.php:84
+#: data/templates/editbookmark.tpl.php:89
#: data/templates/importDelicious.tpl.php:15
#: data/templates/importNetscape.tpl.php:16
msgid "Privacy"
msgstr ""
-#: data/templates/editbookmark.tpl.php:87
+#: data/templates/editbookmark.tpl.php:92
#: data/templates/importDelicious.tpl.php:18
#: data/templates/importNetscape.tpl.php:19
msgid "Public"
msgstr ""
-#: data/templates/editbookmark.tpl.php:88
+#: data/templates/editbookmark.tpl.php:93
msgid "Shared with Watch List"
msgstr ""
-#: data/templates/editbookmark.tpl.php:89
+#: data/templates/editbookmark.tpl.php:94
#: data/templates/importDelicious.tpl.php:20
#: data/templates/importNetscape.tpl.php:21
msgid "Private"
msgstr ""
-#: data/templates/editbookmark.tpl.php:102
+#: data/templates/editbookmark.tpl.php:107
msgid "Delete Bookmark"
msgstr ""
-#: data/templates/editbookmark.tpl.php:107
+#: data/templates/editbookmark.tpl.php:112
msgid "edit common description"
msgstr ""
-#: data/templates/editbookmark.tpl.php:134
+#: data/templates/editbookmark.tpl.php:139
msgid "Bookmarklet"
msgstr ""
-#: data/templates/editbookmark.tpl.php:140
+#: data/templates/editbookmark.tpl.php:145
#, php-format
msgid ""
"Click one of the following bookmarklets to add a button you can click "
"whenever you want to add the page you are on to %s"
msgstr ""
-#: data/templates/editbookmark.tpl.php:144
+#: data/templates/editbookmark.tpl.php:149
#, php-format
msgid ""
"Drag one of the following bookmarklets to your browser's bookmarks and click "
"it whenever you want to add the page you are on to %s"
msgstr ""
-#: data/templates/editbookmark.tpl.php:157
#: data/templates/editbookmark.tpl.php:162
+#: data/templates/editbookmark.tpl.php:167
#, php-format
msgid "Post to %s"
msgstr ""
-#: data/templates/editbookmark.tpl.php:158
#: data/templates/editbookmark.tpl.php:163
+#: data/templates/editbookmark.tpl.php:168
#, php-format
msgid "Post to %s (Pop-up)"
msgstr ""
-#: data/templates/editbookmark.tpl.php:168
+#: data/templates/editbookmark.tpl.php:173
#: data/templates/importDelicious.tpl.php:26
#: data/templates/importNetscape.tpl.php:27
#: data/templates/importStructure.tpl.php:16
msgid "Import"
msgstr ""
-#: data/templates/editbookmark.tpl.php:170
+#: data/templates/editbookmark.tpl.php:175
msgid "Import bookmarks from bookmark file"
msgstr ""
-#: data/templates/editbookmark.tpl.php:170
+#: data/templates/editbookmark.tpl.php:175
msgid "Internet Explorer, Mozilla Firefox and Netscape"
msgstr ""
-#: data/templates/editbookmark.tpl.php:171
+#: data/templates/editbookmark.tpl.php:176
msgid "Import bookmarks from del.icio.us"
msgstr ""
@@ -841,7 +841,7 @@ msgid "Edit Tag Description"
msgstr ""
#: data/templates/sidebar.block.tagactions.php:26
-#: www/tagcommondescriptionedit.php:64
+#: www/tagcommondescriptionedit.php:76
msgid "Edit Tag Common Description"
msgstr ""
@@ -1028,12 +1028,12 @@ msgstr ""
msgid "Failed to delete bookmark"
msgstr ""
-#: www/alltags.php:49
+#: www/alltags.php:50
msgid "All Tags"
msgstr ""
-#: www/alltags.php:55 www/bookmarks.php:96 www/populartags.php:52
-#: www/profile.php:51 www/rss.php:67 www/search.php:109 www/watch.php:45
+#: www/alltags.php:56 www/bookmarks.php:96 www/populartags.php:52
+#: www/profile.php:51 www/rss.php:76 www/search.php:109 www/watch.php:45
#: www/watchlist.php:61
#, php-format
msgid "User with username %s was not found"
@@ -1041,7 +1041,7 @@ msgstr ""
#: www/bookmarkcommondescriptionedit.php:51 www/tag2tagadd.php:37
#: www/tag2tagdelete.php:41 www/tag2tagedit.php:33
-#: www/tagcommondescriptionedit.php:43 www/tagedit.php:43
+#: www/tagcommondescriptionedit.php:51 www/tagedit.php:43
msgid "Permission denied."
msgstr ""
@@ -1179,11 +1179,11 @@ msgstr ""
msgid "%s: Recent bookmarks"
msgstr ""
-#: www/index.php:78
+#: www/index.php:75
msgid "Store, share and tag your favourite links"
msgstr ""
-#: www/index.php:79
+#: www/index.php:76
msgid "All Bookmarks"
msgstr ""
@@ -1313,7 +1313,7 @@ msgstr ""
msgid "Registration failed. Please try again."
msgstr ""
-#: www/rss.php:84
+#: www/rss.php:93
#, php-format
msgid "Recent bookmarks posted to %s"
msgstr ""
@@ -1358,11 +1358,11 @@ msgstr ""
msgid "Edit Link Between Tags"
msgstr ""
-#: www/tagcommondescriptionedit.php:55
+#: www/tagcommondescriptionedit.php:62
msgid "Tag common description updated"
msgstr ""
-#: www/tagcommondescriptionedit.php:58
+#: www/tagcommondescriptionedit.php:67
msgid "Failed to update the tag common description"
msgstr ""
diff --git a/data/templates/admin.tpl.php b/data/templates/admin.tpl.php
index c8d47e8..50680f6 100644
--- a/data/templates/admin.tpl.php
+++ b/data/templates/admin.tpl.php
@@ -11,7 +11,7 @@ foreach($users as $user) {
echo '<div class="link">';
echo '<a href="'.createURL('profile', $user->getUsername()).'">'.$user->getUsername().'</a>';
- echo ' - <span title='. T_('Public/Shared/Private') .'>'. $user->getNbBookmarks('public') .' / '. $user->getNbBookmarks('shared') .' / '. $user->getNbBookmarks('private') .' '. T_('bookmark(s)') .'</span>';
+ echo ' - <span title="'. T_('Public/Shared/Private') .'">'. $user->getNbBookmarks('public') .' / '. $user->getNbBookmarks('shared') .' / '. $user->getNbBookmarks('private') .' '. T_('bookmark(s)') .'</span>';
echo '</div>';
if($user->getUsername() != $currentUser->getUsername()) {
diff --git a/data/templates/bookmarkcommondescriptionedit.tpl.php b/data/templates/bookmarkcommondescriptionedit.tpl.php
index af5909a..807c58b 100644
--- a/data/templates/bookmarkcommondescriptionedit.tpl.php
+++ b/data/templates/bookmarkcommondescriptionedit.tpl.php
@@ -30,7 +30,8 @@ window.onload = function() {
if(strlen($description['cdDatetime'])>0) {
echo T_('Last modification:').' '.$description['cdDatetime'].', ';
$lastUser = $userservice->getUser($description['uId']);
- echo '<a href="'.createURL('profile', $lastUser['username']).'">'.$lastUser['username'].'</a>';
+ echo '<a href="'.createURL('profile', $lastUser['username']).'">'
+ . SemanticScuttle_Model_UserArray::getName($lastUser) . '</a>';
}
?>
</td>
diff --git a/data/templates/bookmarklet.inc.php b/data/templates/bookmarklet.inc.php
new file mode 100644
index 0000000..9867745
--- /dev/null
+++ b/data/templates/bookmarklet.inc.php
@@ -0,0 +1,117 @@
+<h3><?php echo T_('Bookmarklet'); ?></h3>
+<p id="bookmarklet"></p>
+<script type="text/javascript">
+//<![CDATA[
+var browser = navigator.appName;
+jQuery(function($) {
+if (browser == "Opera") {
+ $('#bookmarklet').append(
+ <?php echo json_encode(
+ sprintf(
+ T_("Click one of the following bookmarklets to add a button you can click whenever you want to add the page you are on to %s") . ':',
+ $GLOBALS['sitename']
+ )
+ ); ?>
+ );
+} else {
+ $('#bookmarklet').append(
+ <?php echo json_encode(
+ sprintf(
+ T_("Drag one of the following bookmarklets to your browser's bookmarks and click it whenever you want to add the page you are on to %s") . ':',
+ $GLOBALS['sitename']
+ )
+ );
+ ?>
+ );
+}
+});
+//]]>
+</script>
+<script type="text/javascript">
+//<![CDATA[
+var selection = '';
+if (window.getSelection) {
+ selection = 'window.getSelection()';
+} else if (document.getSelection) {
+ selection = 'document.getSelection()';
+} else if (document.selection) {
+ selection = 'document.selection.createRange().text';
+}
+if (browser == "Opera") {
+ $('#bookmarklet').append(
+ '<ul>'
+ + '<li>'
+ + '<a class="bookmarklet" href="'
+ + '<?php
+$popupLink = 'javascript:'
+ . "location.href='"
+ . createURL('bookmarks', $GLOBALS['user'])
+ . '?action=add'
+ . "&address='+encodeURIComponent(document.location.href)+'"
+ . "&title='+encodeURIComponent(document.title)+'"
+ . "&description='+encodeURIComponent(SELECTION)"
+ . ";";
+$link = 'opera:/button/'
+ //Opera command
+ . 'Go to page'
+ //command parameter 1
+ . ',"' . rawurlencode($popupLink) . '"'
+ //command parameter 2
+ . ','
+ //button title
+ . ',"Post to ' . fixOperaButtonName($GLOBALS['sitename']) . '"'
+ //button icon name
+ . ',"Scuttle"';
+echo jsEscTitle(htmlspecialchars($link));
+?>'.replace('SELECTION', selection)
+ + '"><?php echo jsEscTitle(sprintf(T_('Post to %s'), $GLOBALS['sitename'])); ?></a>'
+ + '</li>'
+ + '<li>'
+ + '<a class="bookmarklet" href="'
+ + '<?php
+$popupLink = 'javascript:'
+ . 'open('
+ . "'" . createURL('bookmarks', $GLOBALS['user'])
+ . '?action=add'
+ . '&popup=1'
+ . "&address='+encodeURIComponent(document.location.href)+'"
+ . "&title='+encodeURIComponent(document.title)+'"
+ . "&description='+encodeURIComponent(SELECTION)"
+ . ","
+ . "'" . htmlspecialchars(jsEscTitle($GLOBALS['sitename'])) . "',"
+ . "'modal=1,status=0,scrollbars=1,toolbar=0,resizable=1,width=790,height=465"
+ . ",left='+(screen.width-790)/2+',top='+(screen.height-425)/2"
+ . ");void 0";
+$link = 'opera:/button/'
+ . 'Go to page'
+ . ',"' . rawurlencode($popupLink) . '"'
+ . ','
+ . ',"Post to ' . fixOperaButtonName($GLOBALS['sitename']) . ' (Pop-up)"'
+ . ',"Scuttle"';
+echo jsEscTitle(htmlspecialchars($link));
+?>'.replace('SELECTION', selection)
+ + '"><?php echo jsEscTitle(sprintf(T_('Post to %s (Pop-up)'), $GLOBALS['sitename'])); ?></a>'
+ + '</li>'
+ + '</ul>'
+ );
+} else {
+ $('#bookmarklet').append(
+ '<ul>'
+ + '<li><a class="bookmarklet" href="javascript:x=document;a=encodeURIComponent(x.location.href);t=encodeURIComponent(x.title);d=encodeURIComponent('+selection+');location.href=\'<?php echo createURL('bookmarks', $GLOBALS['user']); ?>?action=add&amp;address=\'+a+\'&amp;title=\'+t+\'&amp;description=\'+d;void 0;"><?php echo jsEscTitle(sprintf(T_('Post to %s'), $GLOBALS['sitename'])); ?><\/a><\/li>'
+ + '<li>'
+ + '<a class="bookmarklet" href="'
+ + 'javascript:x=document;'
+ + 'a=encodeURIComponent(x.location.href);'
+ + 't=encodeURIComponent(x.title);'
+ + 'd=encodeURIComponent('+selection+');'
+ + 'open('
+ + '\'<?php echo createURL('bookmarks', $GLOBALS['user']); ?>?action=add&amp;popup=1&amp;address=\'+a+\'&amp;title=\'+t+\'&amp;description=\'+d,\'<?php echo htmlspecialchars(jsEscTitleDouble($GLOBALS['sitename'])); ?>\',\'modal=1,status=0,scrollbars=1,toolbar=0,resizable=1,width=790,height=465,left=\'+(screen.width-790)/2+\',top=\'+(screen.height-425)/2'
+ + ');void 0;">'
+ + '<?php echo jsEscTitle(sprintf(T_('Post to %s (Pop-up)'), $GLOBALS['sitename'])); ?>'
+ + '</a>'
+ + '</li>'
+ + '</ul>'
+ );
+}
+//]]>
+</script>
diff --git a/data/templates/bookmarks.tpl.php b/data/templates/bookmarks.tpl.php
index dab2f37..55d6a0f 100644
--- a/data/templates/bookmarks.tpl.php
+++ b/data/templates/bookmarks.tpl.php
@@ -1,14 +1,30 @@
<?php
+/**
+ * Show a list of bookmarks.
+ *
+ * SemanticScuttle - your social bookmark manager.
+ *
+ * PHP version 5.
+ *
+ * @category Bookmarking
+ * @package SemanticScuttle
+ * @subcategory Templates
+ * @author Benjamin Huynh-Kim-Bang <mensonge@users.sourceforge.net>
+ * @author Christian Weiske <cweiske@cweiske.de>
+ * @author Eric Dane <ericdane@users.sourceforge.net>
+ * @license GPL http://www.gnu.org/licenses/gpl.html
+ * @link http://sourceforge.net/projects/semanticscuttle
+ */
/* Service creation: only useful services are created */
-$bookmarkservice =SemanticScuttle_Service_Factory::get('Bookmark');
-$tagservice =SemanticScuttle_Service_Factory::get('Tag');
-$cdservice =SemanticScuttle_Service_Factory::get('CommonDescription');
+$bookmarkservice = SemanticScuttle_Service_Factory::get('Bookmark');
+$tagservice = SemanticScuttle_Service_Factory::get('Tag');
+$cdservice = SemanticScuttle_Service_Factory::get('CommonDescription');
-$pageName = isset($pageName)?$pageName:"";
-$user = isset($user)?$user:"";
-$currenttag = isset($currenttag)?$currenttag:"";
+$pageName = isset($pageName) ? $pageName : '';
+$user = isset($user) ? $user : '';
+$currenttag = isset($currenttag) ? $currenttag : '';
$this->includeTemplate($GLOBALS['top_include']);
@@ -46,12 +62,16 @@ if($currenttag!= '' && $cdservice->getLastTagDescription($currenttag)) {
}
//common tag description edit
-if($userservice->isLoggedOn()) {
- if($currenttag!= '' && ($GLOBALS['enableCommonTagDescriptionEditedByAll'] || $currentUser->isAdmin())) {
+if ($userservice->isLoggedOn()) {
+ if ($currenttag != ''
+ && ($GLOBALS['enableCommonTagDescriptionEditedByAll']
+ || $currentUser->isAdmin()
+ )
+ ) {
echo ' <a href="'. createURL('tagcommondescriptionedit', $currenttag).'" title="'.T_('Edit the common description of this tag').'">';
echo !is_array($cDescription) || strlen($cDescription['cdDescription'])==0?T_('Edit the common description of this tag'):'';
echo ' <img src="'.ROOT.'images/b_edit.png" /></a>';
- } elseif(isset($hash)) {
+ } else if (isset($hash)) {
echo ' (<a href="'.createURL('bookmarkcommondescriptionedit', $hash).'" title="'.T_('Edit the common description of this bookmark').'">';
echo T_('Edit the common description of this bookmark').'</a>)';
}
@@ -101,54 +121,54 @@ $votingSort = 'voting_desc';
switch(getSortOrder()) {
case 'date_asc':
- $dateArrow = ' &uarr;';
+ $dateArrow = ' ↑';
$dateSort = 'date_desc';
break;
case 'title_asc':
- $titleArrow = ' &uarr;';
+ $titleArrow = ' ↑';
$titleSort = 'title_desc';
break;
case 'title_desc':
- $titleArrow = ' &darr;';
+ $titleArrow = ' ↓';
$titleSort = 'title_asc';
break;
case 'voting_asc':
- $votingArrow = ' &uarr;';
+ $votingArrow = ' ↑';
$votingSort = 'voting_desc';
break;
case 'voting_desc':
- $votingArrow = ' &darr;';
+ $votingArrow = ' ↓';
$votingSort = 'voting_asc';
break;
case 'date_desc':
default:
- $dateArrow = ' &darr;';
+ $dateArrow = ' ↓';
$dateSort = 'date_asc';
break;
}
?>
-<a href="?sort=<?php echo $dateSort ?>"><?php echo T_("Date").$dateArrow; ?></a>
-<span>/</span>
-<a href="?sort=<?php echo $titleSort ?>"><?php echo T_("Title").$titleArrow; ?></a>
-<span>/</span>
+ <a href="?sort=<?php echo $dateSort ?>"><?php echo T_("Date").$dateArrow; ?></a>
+ <span>/</span>
+ <a href="?sort=<?php echo $titleSort ?>"><?php echo T_("Title").$titleArrow; ?></a>
+ <span>/</span>
<?php if ($GLOBALS['enableVoting']) { ?>
-<a href="?sort=<?php echo $votingSort ?>"><?php echo T_("Voting").$votingArrow; ?></a>
-<span>/</span>
+ <a href="?sort=<?php echo $votingSort ?>"><?php echo T_("Voting").$votingArrow; ?></a>
+ <span>/</span>
<?php } ?>
<?php
-if($currenttag!= '') {
- if($user!= '') {
+if ($currenttag!= '') {
+ if ($user!= '') {
echo ' - ';
echo '<a href="'. createURL('tags', $currenttag) .'">';
echo T_('Bookmarks from other users for this tag').'</a>';
//echo T_(' for these tags');
- } else if($userservice->isLoggedOn()){
+ } else if ($userservice->isLoggedOn()){
echo ' - ';
echo '<a href="'. createURL('bookmarks', $currentUser->getUsername().'/'.$currenttag) .'">';
echo T_('Only your bookmarks for this tag').'</a>';
@@ -199,7 +219,10 @@ if($currenttag!= '') {
$brss = '';
$size = count($rsschannels);
for ($i = 0; $i < $size; $i++) {
- $brss = '<a style="background:#FFFFFF" href="'. $rsschannels[$i][1] .'" title="' . htmlspecialchars($rsschannels[$i][0]) . '"><img src="'. ROOT .'images/rss.gif" width="16" height="16" alt="'. htmlspecialchars($rsschannels[$i][0]) .'" /></a>';
+ $brss = '<a style="background:#FFFFFF" href="'. htmlspecialchars($rsschannels[$i][1]) . '"'
+ . ' title="' . htmlspecialchars($rsschannels[$i][0]) . '">'
+ . '<img src="' . ROOT . 'images/rss.gif" width="16" height="16" alt="' . htmlspecialchars($rsschannels[$i][0]) .'"/>'
+ . '</a>';
}
$pagesBanner = '<p class="paging">'. $bfirst .'<span> / </span>'. $bprev .'<span> / </span>'. $bnext .'<span> / </span>'. $blast .'<span> / </span>'. sprintf(T_('Page %d of %d'), $page, $totalpages) ." ". $brss ." </p>\n";
@@ -213,10 +236,8 @@ if($currenttag!= '') {
-<ol <?php echo ($start > 0 ? ' start="'. ++$start .'"' : ''); ?>
- id="bookmarks">
-
- <?php
+<ol<?php echo ($start > 0 ? ' start="'. ++$start .'"' : ''); ?> id="bookmarks">
+<?php
$addresses = array();
foreach ($bookmarks as $key => &$row) {
$addresses[$row['bId']] = $row['bAddress'];
@@ -253,35 +274,52 @@ if($currenttag!= '') {
$tagsForCopy = '';
$tags = $row['tags'];
foreach ($tags as $tkey => &$tag) {
- $cats .= '<a href="'. sprintf($cat_url, filter($row['username'], 'url'), filter($tag, 'url')) .'" rel="tag">'. filter($tag) .'</a>, ';
- $tagsForCopy.= $tag.',';
+ $tagcaturl = sprintf(
+ $cat_url,
+ filter($row['username'], 'url'),
+ filter($tag, 'url')
+ );
+ $cats .= sprintf(
+ '<a href="%s" rel="tag">%s</a>, ',
+ $tagcaturl, filter($tag)
+ );
+ $tagsForCopy .= $tag . ',';
}
$cats = substr($cats, 0, -2);
if ($cats != '') {
- $cats = ' '.T_('Tags:').' '. $cats;
+ $cats = T_('Tags:') . ' ' . $cats;
}
// Edit and delete links
$edit = '';
if ($bookmarkservice->editAllowed($row)) {
- $edit = ' - <a href="'. createURL('edit', $row['bId']) .'">'. T_('Edit') .'</a><script type="text/javascript">document.write(" - <a href=\"#\" onclick=\"deleteBookmark(this, '. $row['bId'] .'); return false;\">'. T_('Delete') .'<\/a>");</script>';
+ $edit = ' - <a href="' . createURL('edit', $row['bId']) . '">'
+ . T_('Edit')
+ . '</a>'
+ . ' <a href="#" onclick="deleteBookmark(this, '. $row['bId'] .'); return false;">'
+ . T_('Delete')
+ .'</a>';
}
// Last update
- $update = ' <small title="'. T_('Last update') .'">('. date($GLOBALS['shortdate'], strtotime($row['bModified'])). ') </small>';
+ $update = ' <small title="'. T_('Last update') .'">('. date($GLOBALS['shortdate'], strtotime($row['bModified'])). ') </small>';
// User attribution
- $copy = ' '. T_('by'). ' ';
- if($userservice->isLoggedOn() && $currentUser->getUsername() == $row['username']) {
- $copy.= T_('you');
+ $copy = ' ' . T_('by') . ' ';
+ if ($userservice->isLoggedOn()
+ && $currentUser->getUsername() == $row['username']
+ ) {
+ $copy .= T_('you');
} else {
- $copy.= '<a href="'. createURL('bookmarks', $row['username']) .'">'. $row['username'] .'</a>';
+ $copy .= '<a href="' . createURL('bookmarks', $row['username']) . '">'
+ . SemanticScuttle_Model_UserArray::getName($row)
+ . '</a>';
}
- // Udders!
+ // others
if (!isset($hash)) {
$others = $otherCounts[$row['bAddress']];
- $ostart = '<a href="'. createURL('history', $row['bHash']) .'">';
+ $ostart = '<a href="' . createURL('history', $row['bHash']) . '">';
$oend = '</a>';
switch ($others) {
case 0:
@@ -300,7 +338,10 @@ if($currenttag!= '') {
&& !$existence[$row['bAddress']]
) {
$copy .= ' - <a href="'
- . createURL('bookmarks', $currentUser->getUsername() .'?action=add&amp;copyOf='. $row['bId'])
+ . createURL(
+ 'bookmarks',
+ $currentUser->getUsername()
+ . '?action=add&amp;copyOf=' . $row['bId'])
. '" title="'.T_('Copy this bookmark to YOUR bookmarks.').'">'
. T_('Copy')
. '</a>';
@@ -321,11 +362,11 @@ if($currenttag!= '') {
// Admin specific design
if ($userservice->isAdmin($row['username']) && $GLOBALS['enableAdminColors']) {
- $adminBgClass = 'class="adminBackground"';
- $adminStar = ' <img src="'. ROOT .'images/logo_24.gif" width="12px" title="'. T_('This bookmark is certified by an admin user.') .'" />';
+ $adminBgClass = ' class="adminBackground"';
+ $adminStar = ' <img src="'. ROOT .'images/logo_24.gif" width="12px" title="'. T_('This bookmark is certified by an admin user.') .'" />';
} else {
$adminBgClass = '';
- $adminStar = '';
+ $adminStar = '';
}
// Private Note (just visible by the owner and his/her contacts)
@@ -346,13 +387,16 @@ if($currenttag!= '') {
}
// Output
- echo '<li class="xfolkentry'. $access .'" >'."\n";
+ echo ' <li class="xfolkentry'. $access .'">'."\n";
include 'bookmarks-thumbnail.inc.tpl.php';
include 'bookmarks-vote.inc.tpl.php';
- echo '<div '.$adminBgClass.' >';;
+ echo ' <div' . $adminBgClass . '>' . "\n";
- echo '<div class="link"><a href="'. htmlspecialchars($address) .'"'. $rel .' class="taggedlink" target="_blank">'. filter($row['bTitle']) ."</a>" . $adminStar . "</div>\n";
+ echo ' <div class="link">'
+ . '<a href="'. htmlspecialchars($address) .'"'. $rel .' class="taggedlink">'
+ . filter($row['bTitle'])
+ . '</a>' . $adminStar . "</div>\n";
if ($row['bDescription'] == '') {
$bkDescription = $GLOBALS['blankDescription'];
} else {
@@ -362,17 +406,23 @@ if($currenttag!= '') {
$bkDescription = preg_replace('@((http|https|ftp)://.*?)( |\r|$)@', '<a href="$1" rel="nofollow">$1</a>$3', $bkDescription); // make url clickable
}
- echo '<div class="description">'. nl2br($bkDescription) ."</div>\n";
- //if(!isset($hash)) {
- echo '<div class="address">' . shortenString($oaddress) . '</div>';
- //}
-
- echo '<div class="meta">'. $cats . $copy . $edit . $update ."</div>\n";
- echo $privateNoteField!=''?'<div class="privateNote" title="'. T_('Private Note on this bookmark') .'">'.$privateNoteField."</div>\n":'';
+ echo ' <div class="description">'. nl2br($bkDescription) ."</div>\n";
+ echo ' <div class="address">' . shortenString($oaddress) . "</div>\n";
+
+ echo ' <div class="meta">'
+ . $cats . "\n"
+ . $copy . "\n"
+ . $edit . "\n"
+ . $update . "\n"
+ . " </div>\n";
+ echo $privateNoteField != ''
+ ? ' <div class="privateNote" title="'. T_('Private Note on this bookmark') .'">'.$privateNoteField."</div>\n"
+ : '';
+ echo ' ';
include 'bookmarks-vote-horizontal.inc.tpl.php';
- echo '</div>';
+ echo " </div>\n";
- echo "</li>\n";
+ echo " </li>\n";
}
?>
diff --git a/data/templates/dynamictags.inc.php b/data/templates/dynamictags.inc.php
index b18565b..8cf07c1 100644
--- a/data/templates/dynamictags.inc.php
+++ b/data/templates/dynamictags.inc.php
@@ -36,28 +36,40 @@ $allPopularTagsCount = count($allPopularTags);
// function printing the cloud
-function writeTagsProposition($tagsCloud, $title) {
- echo 'document.write(\'<div class="collapsible">\');';
- echo 'document.write(\'<h3>'. $title .'<\/h3>\');';
- echo 'document.write(\'<p id="popularTags" class="tags">\');';
+function writeTagsProposition($tagsCloud, $title)
+{
+ static $id = 0;
+ ++$id;
+
+ echo <<<JS
+ $('.edit-tagclouds')
+ .append(
+'<div class="collapsible" id="edit-tagcloud-$id">'
++ ' <h3>$title</h3>'
++ ' <p class="popularTags tags"></p>'
++ '</div>');
+JS;
$taglist = '';
- foreach(array_keys($tagsCloud) as $key) {
- $row =& $tagsCloud[$key];
+ foreach (array_keys($tagsCloud) as $key) {
+ $row = $tagsCloud[$key];
$entries = T_ngettext('bookmark', 'bookmarks', $row['bCount']);
- $taglist .= '<span title="'. $row['bCount'] .' '. $entries .'" style="font-size:'. $row['size'] .'" onclick="addTag(this)">'. filter($row['tag']) .'<\/span> ';
+ $taglist .= '<span'
+ . ' title="'. $row['bCount'] . ' ' . $entries . '"'
+ . ' style="font-size:' . $row['size'] . '"'
+ . ' onclick="addTag(this)">'
+ . filter($row['tag'])
+ . '</span> ';
}
-
- echo 'document.write(\''. $taglist .'\');';
- echo 'document.write(\'<\/p>\');';
- echo 'document.write(\'<\/div>\');';
-
+ echo '$(\'#edit-tagcloud-' . $id . ' p\').append('
+ . json_encode($taglist)
+ . ");\n";
}
if ($allPopularTagsCount > 0 || $userPopularTagsCount > 0 ) { ?>
-
<script type="text/javascript">
+//<![CDATA[
Array.prototype.contains = function (ele) {
for (var i = 0; i < this.length; i++) {
if (this[i] == ele) {
@@ -87,20 +99,26 @@ function addonload(addition) {
}
}
-addonload(
- function () {
- var taglist = document.getElementById('tags');
- var tags = taglist.value.split(', ');
+jQuery(function($) {
+<?php
+if ($userPopularTagsCount > 0) {
+ writeTagsProposition($userPopularTagsCloud, T_('Popular Tags'));
+}
+if ($allPopularTagsCount > 0) {
+ writeTagsProposition($allPopularTagsCloud, T_('Popular Tags From All Users'));
+}
+?>
+ var taglist = $('#tags');
+ var tags = taglist.val().split(', ');
- var populartags = document.getElementById('popularTags').getElementsByTagName('span');
+ var populartags = $('.edit-tagclouds span');
for (var i = 0; i < populartags.length; i++) {
if (tags.contains(populartags[i].innerHTML)) {
populartags[i].className = 'selected';
}
}
- }
-);
+});
function addTag(ele) {
var thisTag = ele.innerHTML;
@@ -122,20 +140,9 @@ function addTag(ele) {
document.getElementById('tags').focus();
}
-
-<?php
-if( $userPopularTagsCount > 0) {
- writeTagsProposition($userPopularTagsCloud, T_('Popular Tags'));
-}
-if( $allPopularTagsCount > 0) {
- writeTagsProposition($allPopularTagsCloud, T_('Popular Tags From All Users'));
-}
-
-
-?>
-
+//]]>
</script>
-
+<div class="edit-tagclouds"></div>
<?php
}
?>
diff --git a/data/templates/editbookmark.tpl.php b/data/templates/editbookmark.tpl.php
index c58bd1b..8b71230 100644
--- a/data/templates/editbookmark.tpl.php
+++ b/data/templates/editbookmark.tpl.php
@@ -16,33 +16,41 @@ switch ($row['bStatus']) {
break;
}
-$this->includeTemplate("dojo.inc");
-
function jsEscTitle($title)
{
return addcslashes($title, "'");
}
-?>
-
-
+function jsEscTitleDouble($title)
+{
+ return addcslashes(addcslashes($title, "'"), "'\\");
+}
+function fixOperaButtonName($name) {
+ //yes, opera has problems with double quotes in button names
+ return str_replace('"', "''", $name);
+}
-<script type="text/javascript">
-//window.onload = function() {
-// document.getElementById("address").focus();
-//}
-</script>
+if (is_array($row['tags'])) {
+ $row['tags'] = implode(', ', $row['tags']);
+}
+$ajaxUrl = ROOT . 'ajax/'
+ . (
+ ($GLOBALS['adminsAreAdvisedTagsFromOtherAdmins'] && $currentUser->isAdmin())
+ ? 'getadmintags'
+ : 'getcontacttags'
+ ) . '.php';
+?>
<form action="<?php echo $formaction; ?>" method="post">
<table>
<tr>
<th align="left"><?php echo T_('Address'); ?></th>
<td><input type="text" id="address" name="address" size="75" maxlength="65535" value="<?php echo filter($row['bAddress'], 'xml'); ?>" onblur="useAddress(this)" /></td>
- <td>&larr; <?php echo T_('Required'); ?></td>
+ <td>← <?php echo T_('Required'); ?></td>
</tr>
<tr>
<th align="left"><?php echo T_('Title'); ?></th>
<td><input type="text" id="titleField" name="title" size="75" maxlength="255" value="<?php echo filter($row['bTitle'], 'xml'); ?>" onkeypress="this.style.backgroundImage = 'none';" /></td>
- <td>&larr; <?php echo T_('Required'); ?></td>
+ <td>← <?php echo T_('Required'); ?></td>
</tr>
<tr>
<th align="left">
@@ -50,7 +58,7 @@ function jsEscTitle($title)
<a onclick="var nz = document.getElementById('privateNoteZone'); nz.style.display='';this.style.display='none';"><?php echo T_("Add Note"); ?></a>
</th>
<td><textarea name="description" id="description" rows="5" cols="63" ><?php echo filter($row['bDescription'], 'xml'); ?></textarea></td>
- <td>&larr; <?php echo T_('You can use anchors to delimite attributes. for example: [publisher]blah[/publisher] '); ?>
+ <td>← <?php echo T_('You can use anchors to delimite attributes. for example: [publisher]blah[/publisher] '); ?>
<?php if(count($GLOBALS['descriptionAnchors'])>0): ?>
<br /><br />
<?php echo T_('Suggested anchors: '); ?>
@@ -67,23 +75,23 @@ function jsEscTitle($title)
<tr id="privateNoteZone" <?php if(strlen($row['bPrivateNote'])==0):?>style="display:none"<?php endif; ?>>
<th align="left"><?php echo T_('Private Note'); ?></th>
<td><textarea name="privateNote" id="privateNote" rows="1" cols="63" ><?php echo filter($row['bPrivateNote'], 'xml'); ?></textarea></td>
- <td>&larr; <?php echo T_('Just visible by you and your contacts.'); ?>
+ <td>← <?php echo T_('Just visible by you and your contacts.'); ?>
</td>
</tr>
<tr>
<th align="left"><?php echo T_('Tags'); ?></th>
<td class="scuttletheme">
- <span dojoType="dojo.data.ItemFileReadStore" jsId="memberTagStore" url="<?php echo ROOT?>ajax/<?php echo ($GLOBALS['adminsAreAdvisedTagsFromOtherAdmins'] && $currentUser->isAdmin())?'getadmintags':'getcontacttags'?>.php"></span>
- <input type="text" dojoType="js.MultiComboBox" id="tags" name="tags" size="75" value="<?php echo filter(implode(', ', $row['tags']), 'xml'); ?>" store="memberTagStore" delimiter="," searchAttr="tag" hasDownArrow="false" queryExpr="*${0}*" autoComplete="false" highlightMatch="all"/></td>
- <td>&larr; <?php echo T_('Comma-separated'); ?></td>
+ <input type="text" id="tags" name="tags" size="75" value="<?php echo filter($row['tags'], 'xml'); ?>"/>
+ </td>
+ <td>← <?php echo T_('Comma-separated'); ?></td>
</tr>
<tr>
<th></th>
- <td align="right"><small><?php echo T_('Note: use ">" to include one tag in another. e.g.: europe>france>paris')?><small></td>
+ <td align="right"><small><?php echo htmlspecialchars(T_('Note: use ">" to include one tag in another. e.g.: europe>france>paris'))?></small></td>
</tr>
<tr>
<th></th>
- <td align="right"><small><?php echo T_('Note: use "=" to make synonym two tags. e.g.: france=frenchcountry')?><small></td>
+ <td align="right"><small><?php echo T_('Note: use "=" to make synonym two tags. e.g.: france=frenchcountry')?></small></td>
</tr>
<tr>
<th align="left"><?php echo T_('Privacy'); ?></th>
@@ -111,7 +119,7 @@ function jsEscTitle($title)
echo ' (<a href="'.createURL('bookmarkcommondescriptionedit', $row['bHash']).'">';
echo T_('edit common description').'</a>)';
}
-
+
if ($popup) {
?>
<input type="hidden" name="popup" value="1" />
@@ -124,52 +132,83 @@ function jsEscTitle($title)
?>
</td>
<td></td>
-</tr>
-</table>
+ </tr>
+ </table>
</form>
-<?php
-// Dynamic tag selection
-$this->includeTemplate('dynamictags.inc');
+<link href="<?php echo ROOT ?>js/jquery-ui-1.8.11/themes/base/jquery.ui.all.css" rel="stylesheet" type="text/css"/>
-// Bookmarklets and import links
-if (empty($_REQUEST['popup']) && (!isset($showdelete) || !$showdelete)) {
-?>
-
-<h3><?php echo T_('Bookmarklet'); ?></h3>
-<p>
+<script type="text/javascript" src="<?php echo ROOT ?>js/jquery-ui-1.8.11/jquery.ui.core.js"></script>
+<script type="text/javascript" src="<?php echo ROOT ?>js/jquery-ui-1.8.11/jquery.ui.widget.js"></script>
+<script type="text/javascript" src="<?php echo ROOT ?>js/jquery-ui-1.8.11/jquery.ui.position.js"></script>
+<script type="text/javascript" src="<?php echo ROOT ?>js/jquery-ui-1.8.11/jquery.ui.autocomplete.js"></script>
<script type="text/javascript">
-var browser=navigator.appName;
-if (browser == "Opera")
- {
- document.write('<?php echo sprintf(T_("Click one of the following bookmarklets to add a button you can click whenever you want to add the page you are on to %s"), jsEscTitle($GLOBALS['sitename'])); ?>:</p>');
- }
-else
- {
- document.write('<?php echo sprintf(T_("Drag one of the following bookmarklets to your browser's bookmarks and click it whenever you want to add the page you are on to %s"), jsEscTitle($GLOBALS['sitename'])); ?>:</p>');
- }
-var selection = '';
-if (window.getSelection) {
- selection = 'window.getSelection()';
-} else if (document.getSelection) {
- selection = 'document.getSelection()';
-} else if (document.selection) {
- selection = 'document.selection.createRange().text';
-}
-document.write('<ul>');
-if (browser == "Opera")
+//<![CDATA[
+jQuery(document).ready(function() {
+ function split(val)
{
- document.write('<li><a class="bookmarklet" href="opera:/button/Go%20to%20page,%20%22javascript:x=document;a=encodeURIComponent(x.location.href);t=encodeURIComponent(x.title);d=encodeURIComponent('+selection+');location.href=\'<?php echo createURL('bookmarks', $GLOBALS['user']); ?>?action=add&amp;address=\'+a+\'&amp;title=\'+t+\'&amp;description=\'+d;void 0%22;,,%22Post%20to%20<?php echo jsEscTitle($GLOBALS['sitename']); ?>%22,%22Scuttle%22"><?php echo jsEscTitle(sprintf(T_('Post to %s'), $GLOBALS['sitename'])); ?><\/a><\/li>');
- document.write('<li><a class="bookmarklet" href="opera:/button/Go%20to%20page,%20%22javascript:x=document;a=encodeURIComponent(x.location.href);t=encodeURIComponent(x.title);d=encodeURIComponent('+selection+');open(\'<?php echo createURL('bookmarks', $GLOBALS['user']); ?>?action=add&amp;popup=1&amp;address=\'+a+\'&amp;title=\'+t+\'&amp;description=\'+d,\'<?php echo jsEscTitle($GLOBALS['sitename']); ?>\',\'modal=1,status=0,scrollbars=1,toolbar=0,resizable=1,width=790,height=465,left=\'+(screen.width-790)/2+\',top=\'+(screen.height-425)/2);void 0;%22,,%22Post%20to%20<?php echo urlencode($GLOBALS['sitename']); ?>%20(Pop-up)%22,%22Scuttle%22"><?php echo jsEscTitle(sprintf(T_('Post to %s (Pop-up)'), $GLOBALS['sitename'])); ?><\/a><\/li>');
+ return val.split(/[,=><]\s*/);
}
-else
+
+ function extractLast(term)
{
- document.write('<li><a class="bookmarklet" href="javascript:x=document;a=encodeURIComponent(x.location.href);t=encodeURIComponent(x.title);d=encodeURIComponent('+selection+');location.href=\'<?php echo createURL('bookmarks', $GLOBALS['user']); ?>?action=add&amp;address=\'+a+\'&amp;title=\'+t+\'&amp;description=\'+d;void 0;"><?php echo jsEscTitle(sprintf(T_('Post to %s'), $GLOBALS['sitename'])); ?><\/a><\/li>');
- document.write('<li><a class="bookmarklet" href="javascript:x=document;a=encodeURIComponent(x.location.href);t=encodeURIComponent(x.title);d=encodeURIComponent('+selection+');open(\'<?php echo createURL('bookmarks', $GLOBALS['user']); ?>?action=add&amp;popup=1&amp;address=\'+a+\'&amp;title=\'+t+\'&amp;description=\'+d,\'<?php echo jsEscTitle($GLOBALS['sitename']); ?>\',\'modal=1,status=0,scrollbars=1,toolbar=0,resizable=1,width=790,height=465,left=\'+(screen.width-790)/2+\',top=\'+(screen.height-425)/2);void 0;"><?php echo jsEscTitle(sprintf(T_('Post to %s (Pop-up)'), $GLOBALS['sitename'])); ?><\/a><\/li>');
+ return split(term).pop();
}
-document.write('<\/ul>');
+ //var availableTags = ["c++", "java", "php", "coldfusion", "javascript", "asp", "ruby"];
+
+ jQuery("input#tags").autocomplete({
+ autoFocus: true,
+ minLength: 1,
+
+ source: function(request, response) {
+ // delegate back to autocomplete, but extract the last term
+ var term = extractLast(request.term);
+ if (term.length < this.options.minLength) {
+ return;
+ }
+ response(
+ /*
+ $.ui.autocomplete.filter(
+ availableTags, extractLast(request.term)
+ )
+ */
+ $.getJSON(
+ "<?php echo $ajaxUrl; ?>",
+ { beginsWith: term },
+ response
+ )
+ );
+ },
+
+ focus: function() {
+ // prevent value inserted on focus
+ return false;
+ },
+ select: function(event, ui) {
+ var terms = split(this.value);
+ // remove the current input
+ terms.pop();
+ // add the selected item
+ terms.push(ui.item.value);
+ // add placeholder to get the comma-and-space at the end
+ terms.push("");
+ this.value = terms.join(", ");
+ return false;
+ }
+ });
+});
+//]]>
</script>
+<?php
+// Dynamic tag selection
+$this->includeTemplate('dynamictags.inc');
+
+// Bookmarklets and import links
+if (empty($_REQUEST['popup']) && (!isset($showdelete) || !$showdelete)) {
+
+$this->includeTemplate('bookmarklet.inc.php');
+?>
<h3><?php echo T_('Import'); ?></h3>
<ul>
<li><a href="<?php echo createURL('importNetscape'); ?>"><?php echo T_('Import bookmarks from bookmark file'); ?></a> (<?php echo T_('Internet Explorer, Mozilla Firefox and Netscape'); ?>)</li>
@@ -178,5 +217,5 @@ document.write('<\/ul>');
<?php
}
-$this->includeTemplate($GLOBALS['bottom_include']);
+$this->includeTemplate($GLOBALS['bottom_include']);
?>
diff --git a/data/templates/editprofile.tpl.php b/data/templates/editprofile.tpl.php
index b55d250..2a3c3b8 100644
--- a/data/templates/editprofile.tpl.php
+++ b/data/templates/editprofile.tpl.php
@@ -3,9 +3,7 @@ $this->includeTemplate($GLOBALS['top_include']);
?>
<form action="<?php echo $formaction; ?>" method="post">
-<input type="hidden" name="token" value="<?php echo $token; ?>">
-
-</table>
+<input type="hidden" name="token" value="<?php echo $token; ?>"/>
<h3><?php echo T_('Account Details'); ?></h3>
@@ -28,7 +26,7 @@ $this->includeTemplate($GLOBALS['top_include']);
<tr>
<th align="left"><?php echo T_('E-mail'); ?></th>
<td><input type="text" name="pMail" size="75" value="<?php echo filter($objectUser->getEmail(), 'xml'); ?>" /></td>
- <td>&larr; <?php echo T_('Required'); ?></td>
+ <td>← <?php echo T_('Required'); ?></td>
</tr>
</table>
@@ -58,7 +56,7 @@ $this->includeTemplate($GLOBALS['top_include']);
<th align="left"><?php echo T_('Export bookmarks'); ?></th>
<td>
<a href="../api/export_html.php"><?php echo T_('HTML file (for browsers)')?></a> /
- <a href="../api/posts/all"><?php echo T_('XML file (like del.icio.us)')?></a> /
+ <a href="../api/posts_all.php"><?php echo T_('XML file (like del.icio.us)')?></a> /
<a href="../api/export_csv.php"><?php echo T_('CSV file (for spreadsheet tools)')?></a>
</td>
</tr>
diff --git a/data/templates/sidebar.block.linked.php b/data/templates/sidebar.block.linked.php
index 9e91f93..9aa3cc0 100644
--- a/data/templates/sidebar.block.linked.php
+++ b/data/templates/sidebar.block.linked.php
@@ -1,4 +1,11 @@
<?php
+/*
+ * Used in:
+ * - populartags.php
+ * - bookmarks.php
+ * - alltags.php
+ * - tags.php
+ */
/* Service creation: only useful services are created */
$tag2tagservice =SemanticScuttle_Service_Factory::get('Tag2Tag');
@@ -8,98 +15,52 @@ require_once('sidebar.linkedtags.inc.php');
$user = isset($user)?$user:'';
$userid = isset($userid)?$userid:0;
$currenttag = isset($currenttag)?$currenttag:'';
-$summarizeLinkedTags = isset($summarizeLinkedTags)?$summarizeLinkedTags:false;
-
+//$summarizeLinkedTags = isset($summarizeLinkedTags)?$summarizeLinkedTags:false;
$logged_on_userid = $userservice->getCurrentUserId();
-if ($logged_on_userid === false) {
- $logged_on_userid = NULL;
-}
-
-$explodedTags = array();
-if (strlen($currenttag)>0) {
- $explodedTags = explode('+', $currenttag);
-} else {
- if($summarizeLinkedTags == true) {
- $orphewTags = $tag2tagservice->getOrphewTags('>', $userid, 4, "nb");
- } else {
- $orphewTags = $tag2tagservice->getOrphewTags('>', $userid);
- }
-
- foreach($orphewTags as $orphewTag) {
- $explodedTags[] = $orphewTag['tag'];
- }
-}
-
+$editingMode = $logged_on_userid !== false;
?>
-
+<h2><?php echo T_('Linked Tags'); ?></h2>
+<div id="related">
<?php
-if(($logged_on_userid != null) && ($userid === $logged_on_userid)) {
- $editingMode = true;
-} else {
- $editingMode = false;
-}
-
-$this->includeTemplate("dojo.inc");
-?>
-
-<?php if(count($explodedTags)>0 || $editingMode):?>
-
-<h2><?php
-
-
-echo T_('Linked Tags').' ';
-//if($userid != null) {
-$cUser = $userservice->getUser($userid);
-//echo '<small><a href="'.createURL('alltags', $cUser['username']).'">('.T_('all tags').')</a></small>';
-//}
-?></h2>
-<?php //endif?>
-
-<div id="related"> <?php
-if($editingMode) {
+if ($editingMode) {
echo '<p style="margin-bottom: 13px;text-align:center;">';
echo ' (<a href="'. createURL('tag2tagadd','') .'" rel="tag">'.T_('Add new link').'</a>) ';
echo ' (<a href="'. createURL('tag2tagdelete','') .'" rel="tag">'.T_('Delete link').'</a>)';
echo '</p>';
}
-
-if(strlen($user)==0) {
- $cat_url = createURL('tags', '%2$s');
-}
-
-$stopList = array();
-foreach($explodedTags as $explodedTag) {
- if(!in_array($explodedTag, $stopList)) {
-
-
-
- // fathers tag
- $fatherTags = $tag2tagservice->getLinkedTags($explodedTag, '>', $userid, true);
- if(count($fatherTags)>0) {
- foreach($fatherTags as $fatherTag) {
- echo '<a href="'. sprintf($cat_url, filter($user, 'url'), filter($fatherTag, 'url')) .'" rel="tag">('. filter($fatherTag) .')</a> ';
- }
- }
- /*
- $displayLinkedTags = displayLinkedTags($explodedTag, '>', $userid, $cat_url, $user, $editingMode, null, 1);
- echo $displayLinkedTags['output'];
- if(is_array($displayLinkedTags['stopList'])) {
- $stopList = array_merge($stopList, $displayLinkedTags['stopList']);
- }*/
- echo '<div dojoType="dojo.data.ItemFileReadStore" url="'.ROOT.'ajax/getlinkedtags.php?tag='.filter($explodedTag, 'url').'&amp;uId='.$userid.'" jsid="linkedTagStore" ></div>';
- echo '<div dojoType="dijit.Tree" store="linkedTagStore" labelAttr="name" >';
- echo '<script type="dojo/method" event="onClick" args="item">';
- $returnUrl = sprintf($cat_url, filter($user, 'url'), filter('', 'url'));
- echo 'window.location = "'.$returnUrl.'"+item.name';
- echo '</script>';
- echo '<script type="dojo/method" event="getLabelClass" args="item">';
- echo 'return \'treeTag\';';
- echo '</script>';
- echo '</div>';
- }
-
-}
-?> </div>
-
-<?php endif?>
+?>
+ <div id="related-content"></div>
+ <script type="text/javascript">//<![CDATA[
+jQuery("#related-content")
+.jstree({
+ "themes" : {
+ "theme": "default",
+ "dots": false,
+ "icons": true,
+ "url": '<?php echo ROOT_JS ?>themes/default/style.css'
+ },
+ "json_data" : {
+ "ajax" : {
+ "url": function(node) {
+ //-1 is root
+ parentparam = "";
+ if (node == -1 ) {
+ node = <?php echo json_encode($currenttag); ?>;
+ parentparam = "&parent=true";
+ } else if (node.attr('rel')) {
+ node = node.attr('rel');
+ } else {
+ return;
+ }
+
+ return "<?php echo ROOT ?>ajax/getlinkedtags.php?tag=" + node
+ + parentparam;
+ }
+ }
+ },
+ plugins : [ "themes", "json_data"]
+});
+//]]>
+ </script>
+</div> \ No newline at end of file
diff --git a/data/templates/sidebar.block.menu.php b/data/templates/sidebar.block.menu.php
index ee82997..94a9fa2 100644
--- a/data/templates/sidebar.block.menu.php
+++ b/data/templates/sidebar.block.menu.php
@@ -65,13 +65,13 @@ if (sizeof($menuTags) > 0 || ($userid != 0 && $userid === $logged_on_userid)) {
<?php $cUser = $userservice->getUser($userid); ?>
<?php if($userid>0): ?>
<?php if($userid==$logged_on_userid): ?>
-<p style="text-align:right"><a href="<?php echo createURL('alltags', $cUser['username']); ?>" title="<?php echo T_('See all your tags')?>"><?php echo T_('all your tags'); ?></a> &rarr;</p>
+<p style="text-align:right"><a href="<?php echo createURL('alltags', $cUser['username']); ?>" title="<?php echo T_('See all your tags')?>"><?php echo T_('all your tags'); ?></a> →</p>
<?php else: ?>
-<p style="text-align:right"><a href="<?php echo createURL('alltags', $cUser['username']); ?>" title="<?php echo T_('See all tags from this user')?>"><?php echo T_('all tags from this user'); ?></a> &rarr;</p>
+<p style="text-align:right"><a href="<?php echo createURL('alltags', $cUser['username']); ?>" title="<?php echo T_('See all tags from this user')?>"><?php echo T_('all tags from this user'); ?></a> →</p>
<?php endif; ?>
<?php else : ?>
-<p style="text-align:right"><a href="<?php echo createURL('populartags', $cUser['username']); ?>" title="<?php echo T_('See popular tags')?>"><?php echo T_('Popular Tags'); ?></a> &rarr;</p>
+<p style="text-align:right"><a href="<?php echo createURL('populartags', $cUser['username']); ?>" title="<?php echo T_('See popular tags')?>"><?php echo T_('Popular Tags'); ?></a> →</p>
<?php endif; ?>
</div>
diff --git a/data/templates/sidebar.block.menu2.php b/data/templates/sidebar.block.menu2.php
index 5f06b40..1c177a5 100644
--- a/data/templates/sidebar.block.menu2.php
+++ b/data/templates/sidebar.block.menu2.php
@@ -1,7 +1,4 @@
<?php
-/* Service creation: only useful services are created */
-$tag2tagservice =SemanticScuttle_Service_Factory::get('Tag2Tag');
-
require_once('sidebar.linkedtags.inc.php');
/* Manage input */
@@ -15,44 +12,60 @@ if ($logged_on_userid === false) {
}
-$cat_url = createURL('tags', '%2$s');
+$cat_url = createURL('tags', '%s');
$menu2Tags = $GLOBALS['menu2Tags'];
-if (sizeOf($menu2Tags) > 0) {
- $this->includeTemplate("dojo.inc");
- ?>
+if (count($menu2Tags) > 0) {
+?>
<h2><?php echo T_('Featured Menu Tags');?></h2>
<div id="maintagsmenu"
<?php echo 'title="'.T_('This menu is composed of keywords (tags) organized by admins.').'"'?>>
-
+ <ul>
<?php
-foreach($menu2Tags as $menu2Tag) {
-
- echo '<div dojoType="dojo.data.ItemFileReadStore" url="'.ROOT.'ajax/getadminlinkedtags.php?tag='.filter($menu2Tag, 'url').'" jsid="linkedTagStore" ></div>';
- echo '<div dojoType="dijit.Tree" store="linkedTagStore" labelAttr="name" >';
- echo '<script type="dojo/method" event="onClick" args="item">';
- $returnUrl = sprintf($cat_url, filter($user, 'url'), filter('', 'url'));
- echo 'window.location = "'.$returnUrl.'"+item.name';
- echo '</script>';
- //echo '<script type="dojo/method" event="getLabel" args="item">';
- //echo 'return item.name + "...";';
- //echo '</script>';
- //echo '<script type="dojo/method" event="onMouseOver" args="item">';
- //echo 'i = item.relatedTarget;';
- //echo 'if(i.innerHTML.charAt(i.innerHTML)=="a") alert(i.innerHTML)';
- //echo '</script>';
- //echo '<script type="dojo/method" event="getLabelClass" args="item">';
- //echo 'return \'treeTag\';';
- //echo '</script>';
- echo '</div>';
+//this is unneeded and replaced by the ajax tree anyway. we keep it for
+// non-js browsers
+foreach ($menu2Tags as $menu2Tag) {
+ echo ' <li>'
+ . sprintf(
+ '<a href="%s">%s</a>',
+ sprintf($cat_url, $menu2Tag),
+ $menu2Tag
+ )
+ . '</li>' . "\n";
}
?>
+ </ul>
</div>
-
-
+<script type="text/javascript">
+jQuery("#maintagsmenu")
+.jstree({
+ "themes" : {
+ "theme": "default",
+ "dots": false,
+ "icons": true,
+ "url": '<?php echo ROOT_JS ?>themes/default/style.css'
+ },
+ "json_data" : {
+ "ajax" : {
+ "url": function(node) {
+ //-1 is root
+ if (node == -1 ) {
+ node = "";
+ } else if (node.attr('rel')) {
+ node = node.attr('rel');
+ } else {
+ return;
+ }
+ return "<?php echo ROOT ?>ajax/getadminlinkedtags.php?tag=" + node;
+ }
+ }
+ },
+ plugins : [ "themes", "json_data"]
+});
+</script>
<?php
}
?>
diff --git a/data/templates/sidebar.block.recent.php b/data/templates/sidebar.block.recent.php
index e34f820..1ffeb4d 100644
--- a/data/templates/sidebar.block.recent.php
+++ b/data/templates/sidebar.block.recent.php
@@ -31,7 +31,7 @@ if ($recentTags && count($recentTags) > 0) {
}
echo $contents ."</p>\n";
?>
- <p style="text-align:right"><a href="<?php echo createURL('populartags'); ?>"><?php echo T_('Popular Tags'); ?></a> &rarr;</p>
+ <p style="text-align:right"><a href="<?php echo createURL('populartags'); ?>"><?php echo T_('Popular Tags'); ?></a> →</p>
</div>
<?php
diff --git a/data/templates/sidebar.block.search.php b/data/templates/sidebar.block.search.php
index 7efc935..d3cd8a5 100644
--- a/data/templates/sidebar.block.search.php
+++ b/data/templates/sidebar.block.search.php
@@ -1,35 +1,50 @@
<?php
+/**
+ * Show a list of the last searches.
+ *
+ * SemanticScuttle - your social bookmark manager.
+ *
+ * PHP version 5.
+ *
+ * @category Bookmarking
+ * @package SemanticScuttle
+ * @subcategory Templates
+ * @author Benjamin Huynh-Kim-Bang <mensonge@users.sourceforge.net>
+ * @author Christian Weiske <cweiske@cweiske.de>
+ * @author Eric Dane <ericdane@users.sourceforge.net>
+ * @license GPL http://www.gnu.org/licenses/gpl.html
+ * @link http://sourceforge.net/projects/semanticscuttle
+ */
/* Service creation: only useful services are created */
-$searchhistoryservice =SemanticScuttle_Service_Factory::get('SearchHistory');
+$searchhistoryservice = SemanticScuttle_Service_Factory::get('SearchHistory');
-$logged_on_userid = $userservice->getCurrentUserId();
-if ($logged_on_userid === false) {
- $logged_on_userid = NULL;
-}
-
-$lastSearches = $searchhistoryservice->getAllSearches('all', NULL, 3, NULL, true, false);
+$lastSearches = $searchhistoryservice->getAllSearches(
+ 'all', NULL, 3, NULL, true, false
+);
if ($lastSearches && count($lastSearches) > 0) {
?>
<h2><?php echo T_('Last Searches'); ?></h2>
<div id="searches">
-<table>
+ <table>
<?php
foreach ($lastSearches as $row) {
- echo '<tr><td>';
- echo '<a href="' . htmlspecialchars(
- createURL('search', $range.'/'.$row['shTerms'])
- ) . '">';
+ echo ' <tr><td>';
+ echo '<a href="'
+ . htmlspecialchars(createURL('search', $range.'/'.$row['shTerms']))
+ . '">';
echo htmlspecialchars($row['shTerms']);
echo '</a>';
- echo ' <span title="'.T_('Number of bookmarks for this query').'">('.$row['shNbResults'].')</span>';
- echo '</td></tr>';
+ echo ' <span title="'
+ . T_('Number of bookmarks for this query')
+ . '">(' . $row['shNbResults'] . ')</span>';
+ echo '</td></tr>' . "\n";
}
//echo '<tr><td><a href="'.createURL('users').'">...</a></td></tr>';
?>
-</table>
+ </table>
</div>
<?php
}
diff --git a/data/templates/sidebar.block.users.php b/data/templates/sidebar.block.users.php
index 3ad18bc..58fdfb7 100644
--- a/data/templates/sidebar.block.users.php
+++ b/data/templates/sidebar.block.users.php
@@ -18,7 +18,7 @@ if ($lastUsers && count($lastUsers) > 0) {
foreach ($lastUsers as $row) {
echo '<tr><td>';
echo '<a href="'.createURL('profile', $row['username']).'">';
- echo $row['username'];
+ echo SemanticScuttle_Model_UserArray::getName($row);
echo '</a>';
echo ' (<a href="'.createURL('bookmarks', $row['username']).'">'.T_('bookmarks').'</a>)';
echo '</td></tr>';
@@ -27,7 +27,7 @@ foreach ($lastUsers as $row) {
?>
</table>
-<p style="text-align:right"><a href="<?php echo createURL('users'); ?>" title="<?php echo T_('See all users')?>"><?php echo T_('All users'); ?></a> &rarr;</p>
+<p style="text-align:right"><a href="<?php echo createURL('users'); ?>" title="<?php echo T_('See all users')?>"><?php echo T_('All users'); ?></a> →</p>
</div>
<?php
}
diff --git a/data/templates/sidebar.block.watchlist.php b/data/templates/sidebar.block.watchlist.php
index 07b7f15..3af9c5a 100644
--- a/data/templates/sidebar.block.watchlist.php
+++ b/data/templates/sidebar.block.watchlist.php
@@ -16,7 +16,7 @@ foreach($watching as $watchuser) {
?>
<?php if(count($closeContacts)>0):?>
-<h2 title="<?php echo T_('Close contacts are mutual contacts');?>"><?php echo ' &harr; '. T_('Close contacts'); ?></h2>
+<h2 title="<?php echo T_('Close contacts are mutual contacts');?>"><?php echo ' ↔ '. T_('Close contacts'); ?></h2>
<div id="watching">
<ul>
<?php foreach($closeContacts as $watchuser): ?>
@@ -27,7 +27,7 @@ foreach($watching as $watchuser) {
<?php endif; ?>
-<h2><?php echo ' &rarr; '. T_('Watching'); ?></h2>
+<h2><?php echo ' → '. T_('Watching'); ?></h2>
<div id="watching">
<ul>
<?php if($userservice->isLoggedOn() && $currentUser->getUsername() == $user): ?>
@@ -41,7 +41,7 @@ foreach($watching as $watchuser) {
<?php foreach($watching as $watchuser): ?>
<li><a href="<?php echo createURL('bookmarks', $watchuser); ?>"><?php echo $watchuser; ?></a>
<?php if($userservice->isLoggedOn() && $currentUser->getUsername() == $user): ?>
- - <a href="<?php echo createUrl('watch','?contact='.$watchuser); ?>" title="<?php echo T_('Remove this contact'); ?>">x<a/>
+ - <a href="<?php echo createUrl('watch','?contact='.$watchuser); ?>" title="<?php echo T_('Remove this contact'); ?>">x</a>
</li>
<?php endif; ?>
<?php endforeach; ?>
@@ -49,7 +49,7 @@ foreach($watching as $watchuser) {
</ul>
</div>
-<h2><?php echo ' &larr; '. T_('Watched By'); ?></h2>
+<h2><?php echo ' ← '. T_('Watched By'); ?></h2>
<div id="watching">
<ul>
<?php foreach($watchedBy as $watchuser): ?>
diff --git a/data/templates/tag2tagadd.tpl.php b/data/templates/tag2tagadd.tpl.php
index fcbd372..9482007 100644
--- a/data/templates/tag2tagadd.tpl.php
+++ b/data/templates/tag2tagadd.tpl.php
@@ -4,7 +4,7 @@ $this->includeTemplate($GLOBALS['top_include']);
<form action="<?php echo $formaction; ?>" method="post">
-<p align=right" style="float:right">
+<p align="right" style="float:right">
<small style="text-align:right"><?php echo T_('Note: use "=" to make synonym two tags. e.g.: france=frenchcountry')?></small><br/>
<small style="text-align:right"><?php echo T_('Note: use ">" to include one tag in another. e.g.: europe>france>paris')?></small><br/>
</p>
diff --git a/data/templates/tagcommondescriptionedit.tpl.php b/data/templates/tagcommondescriptionedit.tpl.php
index d3a006a..f938f93 100644
--- a/data/templates/tagcommondescriptionedit.tpl.php
+++ b/data/templates/tagcommondescriptionedit.tpl.php
@@ -20,7 +20,8 @@ window.onload = function() {
if(strlen($description['cdDatetime'])>0) {
echo T_('Last modification:').' '.$description['cdDatetime'].', ';
$lastUser = $userservice->getUser($description['uId']);
- echo '<a href="'.createURL('profile', $lastUser['username']).'">'.$lastUser['username'].'</a>';
+ echo '<a href="' . createURL('profile', $lastUser['username']) . '">'
+ . SemanticScuttle_Model_UserArray::getName($lastUser) . '</a>';
}
?>
</td>
diff --git a/data/templates/tagrename.tpl.php b/data/templates/tagrename.tpl.php
index ea8b516..894b964 100644
--- a/data/templates/tagrename.tpl.php
+++ b/data/templates/tagrename.tpl.php
@@ -11,12 +11,12 @@ window.onload = function() {
<tr>
<th align="left"><?php echo T_('Old'); ?></th>
<td><input type="text" name="old" id="old" value="<?php echo $old; ?>" /></td>
- <td>&larr; <?php echo T_('Required'); ?></td>
+ <td>← <?php echo T_('Required'); ?></td>
</tr>
<tr>
<th align="left"><?php echo T_('New'); ?></th>
<td><input type="text" name="new" id="new" value="" /></td>
- <td>&larr; <?php echo T_('Required'); ?></td>
+ <td>← <?php echo T_('Required'); ?></td>
</tr>
<tr>
<td></td>
diff --git a/data/templates/top.inc.php b/data/templates/top.inc.php
index 552c5de..bdd4b1a 100644
--- a/data/templates/top.inc.php
+++ b/data/templates/top.inc.php
@@ -1,30 +1,36 @@
+<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
<head>
- <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+ <meta http-equiv="Content-Type" content="application/xhtml+xml; charset=utf-8" />
<title><?php echo filter($GLOBALS['sitename'] .(isset($pagetitle) ? ' » ' . $pagetitle : '')); ?></title>
<link rel="icon" type="image/png" href="<?php echo ROOT ?>icon.png" />
<link rel="stylesheet" type="text/css" href="<?php echo ROOT ?>scuttle.css" />
<link rel="search" type="application/opensearchdescription+xml" href="<?php echo ROOT ?>api/opensearch.php" title="<?php echo htmlspecialchars($GLOBALS['sitename']) ?>"/>
<?php
-if(isset($rsschannels)) {
+if (isset($rsschannels)) {
$size = count($rsschannels);
for ($i = 0; $i < $size; $i++) {
- echo ' <link rel="alternate" type="application/rss+xml" title="' . htmlspecialchars($rsschannels[$i][0]) . '" href="'. $rsschannels[$i][1] .'" />';
+ echo ' <link rel="alternate" type="application/rss+xml" title="'
+ . htmlspecialchars($rsschannels[$i][0]) . '"'
+ . ' href="'. $rsschannels[$i][1] .'" />';
}
}
?>
- <link rel="stylesheet" type="text/css"
- href="http://ajax.googleapis.com/ajax/libs/dojo/1.2/dijit/themes/nihilo/nihilo.css" />
<?php if (isset($loadjs)) :?>
+<?php if (DEBUG_MODE) : ?>
+ <script type="text/javascript" src="<?php echo ROOT_JS ?>jquery-1.4.2.js"></script>
+ <script type="text/javascript" src="<?php echo ROOT_JS ?>jquery.jstree.js"></script>
+<?php else: ?>
+ <script type="text/javascript" src="<?php echo ROOT_JS ?>jquery-1.4.2.min.js"></script>
+ <script type="text/javascript" src="<?php echo ROOT_JS ?>jquery.jstree.min.js"></script>
+<?php endif ?>
<script type="text/javascript" src="<?php echo ROOT ?>jsScuttle.php"></script>
<?php endif ?>
</head>
-
- <body class="nihilo">
-<!-- the class is used by Dojo widgets -->
+ <body>
<?php
$headerstyle = '';
diff --git a/data/templates/users.tpl.php b/data/templates/users.tpl.php
index c209f94..fa92bef 100644
--- a/data/templates/users.tpl.php
+++ b/data/templates/users.tpl.php
@@ -14,7 +14,14 @@ if ($users && count($users) > 0) {
<?php
$contents = '<';
foreach ($users as $row) {
- echo '<li><strong>'.$row['username'].'</strong> (<a href="'.createURL('profile', $row['username']).'">'.T_('profile').'</a> '.T_('created in').' '.date('M Y',strtotime($row['uDatetime'])).') : <a href="'.createURL('bookmarks', $row['username']).'">'.T_('bookmarks').'</a></li>';
+ echo '<li><strong>'
+ . SemanticScuttle_Model_UserArray::getName($row) . '</strong>'
+ . ' (<a href="' . createURL('profile', $row['username']) . '">'
+ . T_('profile') . '</a> '
+ . T_('created in') . ' '
+ . date('M Y', strtotime($row['uDatetime'])) . ')'
+ . ' : <a href="' . createURL('bookmarks', $row['username']).'">'
+ . T_('bookmarks') . '</a></li>';
}
?>
</ul>
diff --git a/doc/ChangeLog b/doc/ChangeLog
index 5e24f07..273e84b 100644
--- a/doc/ChangeLog
+++ b/doc/ChangeLog
@@ -1,9 +1,34 @@
ChangeLog for SemantiScuttle
============================
-0.9X.X - 2010-XX-XX
+0.98.0 - 2011-XX-XX
-------------------
-- Fix bug getTagsForBookmarks() that fetched all tags
+- Switch to jQuery and drop dojo
+- Fix bug #3187177: Wrong URL / Export XML Bookmarks
+- Fix bug in getTagsForBookmarks() that fetched all tags
+- Implement request #3054906: Show user's full name instead of nickname
+- Implement patch #3059829: update FR_CA translation
+- Show error message on mysqli connection errors
+- Update php-gettext library to 1.0.10
+- api/posts/add respects the "replace" parameter now
+- Fix privacy issue when fetching tags of several users
+
+
+0.97.2 - 2011-02-17
+-------------------
+- Fix bug #3178597: Broken link to context in gsearch admin index page
+- Fix bug #3074816: French translation breaks edit javascript
+- Fix bug #3111254: Search in my_watchlist results in error
+- Fix bug #3073215: Updating bookmark time does not work
+- Fix bug #3065284: AjaxVote problem with Webkit browsers
+
+
+0.97.1 - 2010-09-30
+-------------------
+This is a security release! We do highly recommend to update
+your SemanticScuttle installations!
+
+- Fix bug #3077187: Permission problem when deleting bookmarks
0.97.0 - 2010-06-09
diff --git a/doc/developers/TODO b/doc/developers/TODO
index b788cbd..10a0cf6 100644
--- a/doc/developers/TODO
+++ b/doc/developers/TODO
@@ -39,7 +39,12 @@
- Make users inactive by default when registered newly
- have to be activated by admins (see #1926991)
- Add RDFa to user profile page
+- use recaptcha or alike -> quickform
- tutorial about sidebar
+- update php-gettext
+- index on bookmarks->modified, since created is not used in selects/sort
+ - how to optimize sorts, to prevent mysql filesort? -> index enough?
+ - how to optimize DISTINCT bHash
diff --git a/doc/developers/api b/doc/developers/api
new file mode 100644
index 0000000..efa05fe
--- /dev/null
+++ b/doc/developers/api
@@ -0,0 +1,10 @@
+SemanticScuttle API
+===================
+
+SemanticScuttle tries to implement the delicious API v1 as closely as sensible.
+
+Where it makes sense and the delicious API just does things plainly wrong
+(i.e. when returning a wrong status code on an error), we do it better.
+
+- http://www.delicious.com/help/api
+- http://support.delicious.com/forum/comments.php?DiscussionID=5286&page=1
diff --git a/doc/developers/doc-TODO b/doc/developers/doc-TODO
new file mode 100644
index 0000000..4fac4ab
--- /dev/null
+++ b/doc/developers/doc-TODO
@@ -0,0 +1,9 @@
+- Bookmarklets: Text selection is used as description
+- Tag nesting: Paris > France > World
+- Tag alias: Deutschland = Germany
+
+
+- Which fields are searched?
+ title, description, private note, username, tags
+
+- What are [isbn] and so for?
diff --git a/doc/developers/release-new-version b/doc/developers/release-new-version
index 69530df..4b2540a 100644
--- a/doc/developers/release-new-version
+++ b/doc/developers/release-new-version
@@ -4,8 +4,8 @@ How to release a new version of SemanticScuttle
0. Run unit tests and verify that all of them pass
1. Update doc/ChangeLog
2. Update doc/UPGRADE.txt
-3. Update version in data/templates/about.tpl.php
- and build.xml
+3. Update version in data/templates/about.tpl.php,
+ build.xml and doc/README.txt
4. Create a release zip file via the build script:
Just type "phing".
5. Make a test installation from your zip file with a fresh
diff --git a/doc/developers/translation b/doc/developers/translation
index 401089a..776b5d7 100644
--- a/doc/developers/translation
+++ b/doc/developers/translation
@@ -21,7 +21,7 @@ We keep one base translation file, data/locales/messages.po.
This file is auto-generated via xgettext from all our php source files.
In case you added a new string to the code that needs translation,
update the base translation file by running
-> php scripts/update-translation-base.php.
+> php scripts/update-translation-base.php
After that has been done, the changes to the base messages.po file
need to be merged into the single language translation files,
diff --git a/html.properties b/html.properties
new file mode 100644
index 0000000..8e25cc4
--- /dev/null
+++ b/html.properties
@@ -0,0 +1 @@
+html.sflogo = <a href="http://sourceforge.net/projects/semanticscuttle"><img src="http://sflogo.sourceforge.net/sflogo.php?group_id=211356&amp;type=10" width="80" height="15" alt="Get SemanticScuttle at SourceForge.net. Fast, secure and Free Open Source software downloads" /></a>
diff --git a/scripts/database-dump.php b/scripts/database-dump.php
new file mode 100644
index 0000000..f4f04ac
--- /dev/null
+++ b/scripts/database-dump.php
@@ -0,0 +1,26 @@
+<?php
+/**
+ * Dumps the semanticscuttle database into a file using mysqldump.
+ *
+ * This file is part of
+ * SemanticScuttle - your social bookmark manager.
+ *
+ * PHP version 5.
+ *
+ * @category Bookmarking
+ * @package SemanticScuttle
+ * @author Christian Weiske <cweiske@cweiske.de>
+ * @license GPL http://www.gnu.org/licenses/gpl.html
+ * @link http://sourceforge.net/projects/semanticscuttle
+ */
+require_once dirname(__FILE__) . '/../src/SemanticScuttle/header-standalone.php';
+
+passthru(
+ 'mysqldump'
+ . ' -h' . escapeshellarg($GLOBALS['dbhost'])
+ . ' -u' . escapeshellarg($GLOBALS['dbuser'])
+ . ' -p' . escapeshellarg($GLOBALS['dbpass'])
+ . ' ' . escapeshellarg($GLOBALS['dbname'])
+ . ' > semanticscuttle-dump.sql'
+);
+?> \ No newline at end of file
diff --git a/scripts/database-restore.php b/scripts/database-restore.php
new file mode 100644
index 0000000..6516e71
--- /dev/null
+++ b/scripts/database-restore.php
@@ -0,0 +1,37 @@
+<?php
+/**
+ * Restores the semanticscuttle database from a given file.
+ *
+ * This file is part of
+ * SemanticScuttle - your social bookmark manager.
+ *
+ * PHP version 5.
+ *
+ * @category Bookmarking
+ * @package SemanticScuttle
+ * @author Christian Weiske <cweiske@cweiske.de>
+ * @license GPL http://www.gnu.org/licenses/gpl.html
+ * @link http://sourceforge.net/projects/semanticscuttle
+ */
+
+if (!isset($argv[1])) {
+ echo "Please pass the sql file to restore\n";
+ exit(1);
+}
+$file = $argv[1];
+if (!file_exists($file)) {
+ echo "The file does not exist\n";
+ exit(2);
+}
+
+require_once dirname(__FILE__) . '/../src/SemanticScuttle/header-standalone.php';
+
+passthru(
+ 'mysql'
+ . ' -h' . escapeshellarg($GLOBALS['dbhost'])
+ . ' -u' . escapeshellarg($GLOBALS['dbuser'])
+ . ' -p' . escapeshellarg($GLOBALS['dbpass'])
+ . ' ' . escapeshellarg($GLOBALS['dbname'])
+ . ' < ' . escapeshellarg($file)
+);
+?> \ No newline at end of file
diff --git a/src/SemanticScuttle/Model/RemoteUser.php b/src/SemanticScuttle/Model/RemoteUser.php
new file mode 100644
index 0000000..6d48e3a
--- /dev/null
+++ b/src/SemanticScuttle/Model/RemoteUser.php
@@ -0,0 +1,48 @@
+<?php
+/**
+ * SemanticScuttle - your social bookmark manager.
+ *
+ * PHP version 5.
+ *
+ * @category Bookmarking
+ * @package SemanticScuttle
+ * @author Benjamin Huynh-Kim-Bang <mensonge@users.sourceforge.net>
+ * @author Christian Weiske <cweiske@cweiske.de>
+ * @author Eric Dane <ericdane@users.sourceforge.net>
+ * @license GPL http://www.gnu.org/licenses/gpl.html
+ * @link http://sourceforge.net/projects/semanticscuttle
+ */
+
+/**
+ * Remote User helper methods.
+ *
+ * @category Bookmarking
+ * @package SemanticScuttle
+ * @author Christian Weiske <cweiske@cweiske.de>
+ * @license GPL http://www.gnu.org/licenses/gpl.html
+ * @link http://sourceforge.net/projects/semanticscuttle
+ */
+class SemanticScuttle_Model_RemoteUser
+{
+ /**
+ * Returns the remote user's IP.
+ *
+ * @return string IP address. NULL if not found.
+ */
+ public static function getIp()
+ {
+ $ip = null;
+ if (getenv('REMOTE_ADDR')) {
+ $ip = getenv('REMOTE_ADDR');
+ } else if (getenv('HTTP_CLIENT_IP')) {
+ $ip = getenv('HTTP_CLIENT_IP');
+ } else if (getenv('HTTP_X_FORWARDED_FOR')) {
+ $ip = getenv('HTTP_X_FORWARDED_FOR');
+ }
+
+ return $ip;
+ }
+
+}
+
+?> \ No newline at end of file
diff --git a/src/SemanticScuttle/Model/User.php b/src/SemanticScuttle/Model/User.php
index ed9f454..500f5b1 100644
--- a/src/SemanticScuttle/Model/User.php
+++ b/src/SemanticScuttle/Model/User.php
@@ -15,7 +15,7 @@
/**
* SemanticScuttle user object.
- * Rare fields are filled if required.
+ * Rarely used fields are filled if required.
*
* @category Bookmarking
* @package SemanticScuttle
@@ -133,7 +133,8 @@ class SemanticScuttle_Model_User
}
/**
- * Returns user creation time
+ * Returns user creation time.
+ * UTC/Zulu time zone is used.
*
* @return string Datetime value: "YYYY-MM-DD HH:MM:SS"
*/
diff --git a/src/SemanticScuttle/Model/UserArray.php b/src/SemanticScuttle/Model/UserArray.php
new file mode 100644
index 0000000..a0d9c9b
--- /dev/null
+++ b/src/SemanticScuttle/Model/UserArray.php
@@ -0,0 +1,41 @@
+<?php
+/**
+ * SemanticScuttle - your social bookmark manager.
+ *
+ * PHP version 5.
+ *
+ * @category Bookmarking
+ * @package SemanticScuttle
+ * @author Christian Weiske <cweiske@cweiske.de>
+ * @license GPL http://www.gnu.org/licenses/gpl.html
+ * @link http://sourceforge.net/projects/semanticscuttle
+ */
+
+/**
+ * Mostly static methods that help working with a user row array from database.
+ *
+ * @category Bookmarking
+ * @package SemanticScuttle
+ * @author Christian Weiske <cweiske@cweiske.de>
+ * @license GPL http://www.gnu.org/licenses/gpl.html
+ * @link http://sourceforge.net/projects/semanticscuttle
+ */
+class SemanticScuttle_Model_UserArray
+{
+ /**
+ * Returns full user name as specified in the profile if it is set,
+ * otherwise the nickname/loginname is returned.
+ *
+ * @param array $row User row array from database
+ *
+ * @return string Full name or username
+ */
+ public static function getName($row)
+ {
+ if (isset($row['name']) && $row['name']) {
+ return $row['name'];
+ }
+ return $row['username'];
+ }
+}
+?> \ No newline at end of file
diff --git a/src/SemanticScuttle/Service/Bookmark.php b/src/SemanticScuttle/Service/Bookmark.php
index 364b1a0..a30ad5f 100644
--- a/src/SemanticScuttle/Service/Bookmark.php
+++ b/src/SemanticScuttle/Service/Bookmark.php
@@ -12,6 +12,7 @@
* @license GPL http://www.gnu.org/licenses/gpl.html
* @link http://sourceforge.net/projects/semanticscuttle
*/
+require_once 'SemanticScuttle/Model/RemoteUser.php';
/**
* SemanticScuttle bookmark service.
@@ -44,6 +45,13 @@ class SemanticScuttle_Service_Bookmark extends SemanticScuttle_DbService
+ /**
+ * Creates a new instance. Initializes the table name.
+ *
+ * @param DB $db Database object
+ *
+ * @uses $GLOBALS['tableprefix']
+ */
public function __construct($db)
{
$this->db = $db;
@@ -168,7 +176,10 @@ class SemanticScuttle_Service_Bookmark extends SemanticScuttle_DbService
* Retrieves a bookmark with the given URL.
* DOES NOT RESPECT PRIVACY SETTINGS!
*
- * @param string $hash URL
+ * @param string $address URL to get bookmarks for
+ * @param boolean $all Retrieve from all users (true)
+ * or only bookmarks owned by the current
+ * user (false)
*
* @return mixed Array with bookmark data or false in case
* of an error (i.e. not found).
@@ -176,9 +187,9 @@ class SemanticScuttle_Service_Bookmark extends SemanticScuttle_DbService
* @uses getBookmarkByHash()
* @see getBookmarkByShortname()
*/
- public function getBookmarkByAddress($address)
+ public function getBookmarkByAddress($address, $all = true)
{
- return $this->getBookmarkByHash($this->getHash($address));
+ return $this->getBookmarkByHash($this->getHash($address), $all);
}
@@ -187,16 +198,19 @@ class SemanticScuttle_Service_Bookmark extends SemanticScuttle_DbService
* Retrieves a bookmark with the given hash.
* DOES NOT RESPECT PRIVACY SETTINGS!
*
- * @param string $hash URL hash
+ * @param string $hash URL hash
+ * @param boolean $all Retrieve from all users (true)
+ * or only bookmarks owned by the current
+ * user (false)
*
* @return mixed Array with bookmark data or false in case
* of an error (i.e. not found).
*
* @see getHash()
*/
- public function getBookmarkByHash($hash)
+ public function getBookmarkByHash($hash, $all = true)
{
- return $this->_getbookmark('bHash', $hash, true);
+ return $this->_getbookmark('bHash', $hash, $all);
}
@@ -239,18 +253,18 @@ class SemanticScuttle_Service_Bookmark extends SemanticScuttle_DbService
/**
* Counts bookmarks for a user.
*
- * @param integer $uId User ID
- * @param string $range Range of bookmarks:
- * 'public', 'shared', 'private'
- * or 'all'
+ * @param integer $uId User ID
+ * @param string $status Bookmark visibility/privacy settings:
+ * 'public', 'shared', 'private'
+ * or 'all'
*
* @return integer Number of bookmarks
*/
- public function countBookmarks($uId, $range = 'public')
+ public function countBookmarks($uId, $status = 'public')
{
$sql = 'SELECT COUNT(*) as "0" FROM '. $this->getTableName();
$sql.= ' WHERE uId = ' . intval($uId);
- switch ($range) {
+ switch ($status) {
case 'all':
//no constraints
break;
@@ -425,7 +439,7 @@ class SemanticScuttle_Service_Bookmark extends SemanticScuttle_DbService
* @param string $title Bookmark title
* @param string $description Long bookmark description
* @param string $privateNote Private note for the user.
- * @param string $status Bookmark visibility:
+ * @param string $status Bookmark visibility / privacy settings:
* 0 - public
* 1 - shared
* 2 - private
@@ -453,14 +467,6 @@ class SemanticScuttle_Service_Bookmark extends SemanticScuttle_DbService
$address = $this->normalize($address);
- if (getenv('HTTP_CLIENT_IP')) {
- $ip = getenv('HTTP_CLIENT_IP');
- } else if (getenv('REMOTE_ADDR')) {
- $ip = getenv('REMOTE_ADDR');
- } else {
- $ip = getenv('HTTP_X_FORWARDED_FOR');
- }
-
/*
* Note that if date is NULL, then it's added with a date and
* time of now, and if it's present,
@@ -480,7 +486,7 @@ class SemanticScuttle_Service_Bookmark extends SemanticScuttle_DbService
// Set up the SQL insert statement and execute it.
$values = array(
'uId' => intval($sId),
- 'bIp' => $ip,
+ 'bIp' => SemanticScuttle_Model_RemoteUser::getIp(),
'bDatetime' => $datetime,
'bModified' => $datetime,
'bTitle' => $title,
@@ -548,7 +554,7 @@ class SemanticScuttle_Service_Bookmark extends SemanticScuttle_DbService
* @param string $title Bookmark title
* @param string $description Long bookmark description
* @param string $privateNote Private note for the user.
- * @param string $status Bookmark visibility:
+ * @param string $status Bookmark visibility / privacy setting:
* 0 - public
* 1 - shared
* 2 - private
@@ -570,15 +576,7 @@ class SemanticScuttle_Service_Bookmark extends SemanticScuttle_DbService
return false;
}
- // Get the client's IP address and the date; note that the date is in GMT.
- if (getenv('HTTP_CLIENT_IP'))
- $ip = getenv('HTTP_CLIENT_IP');
- else
- if (getenv('REMOTE_ADDR'))
- $ip = getenv('REMOTE_ADDR');
- else
- $ip = getenv('HTTP_X_FORWARDED_FOR');
-
+ // Get the the date; note that the date is in GMT.
$moddatetime = gmdate('Y-m-d H:i:s', time());
$address = $this->normalize($address);
@@ -589,7 +587,11 @@ class SemanticScuttle_Service_Bookmark extends SemanticScuttle_DbService
if ($bookmark['bAddress'] != $address
&& $this->bookmarkExists($address, $bookmark['uId'])
) {
- message_die(GENERAL_ERROR, 'Could not update bookmark (URL already existing = '.$address.')', '', __LINE__, __FILE__);
+ message_die(
+ GENERAL_ERROR,
+ 'Could not update bookmark (URL already exists: ' . $address . ')',
+ '', __LINE__, __FILE__
+ );
return false;
}
@@ -611,25 +613,33 @@ class SemanticScuttle_Service_Bookmark extends SemanticScuttle_DbService
if (!is_null($date)) {
$datetime = gmdate('Y-m-d H:i:s', strtotime($date));
- $updates[] = array('bDateTime' => $datetime);
+ $updates['bDatetime'] = $datetime;
}
- $sql = 'UPDATE '. $GLOBALS['tableprefix'] .'bookmarks SET '. $this->db->sql_build_array('UPDATE', $updates) .' WHERE bId = '. intval($bId);
+ $sql = 'UPDATE '. $GLOBALS['tableprefix'] . 'bookmarks'
+ . ' SET '. $this->db->sql_build_array('UPDATE', $updates)
+ . ' WHERE bId = ' . intval($bId);
$this->db->sql_transaction('begin');
if (!($dbresult = & $this->db->sql_query($sql))) {
$this->db->sql_transaction('rollback');
- message_die(GENERAL_ERROR, 'Could not update bookmark', '', __LINE__, __FILE__, $sql, $this->db);
+ message_die(
+ GENERAL_ERROR, 'Could not update bookmark',
+ '', __LINE__, __FILE__, $sql, $this->db
+ );
}
- $uriparts = explode('.', $address);
+ $uriparts = explode('.', $address);
$extension = end($uriparts);
unset($uriparts);
$b2tservice = SemanticScuttle_Service_Factory :: get('Bookmark2Tag');
if (!$b2tservice->attachTags($bId, $categories, $fromApi, $extension)) {
$this->db->sql_transaction('rollback');
- message_die(GENERAL_ERROR, 'Could not update bookmark', '', __LINE__, __FILE__, $sql, $this->db);
+ message_die(
+ GENERAL_ERROR, 'Could not update bookmark',
+ '', __LINE__, __FILE__, $sql, $this->db
+ );
}
$this->db->sql_transaction('commit');
@@ -724,7 +734,8 @@ class SemanticScuttle_Service_Bookmark extends SemanticScuttle_DbService
if (SQL_LAYER == 'mysql4') {
$query_1 .= 'SQL_CALC_FOUND_ROWS ';
}
- $query_1 .= 'B.*, U.'. $userservice->getFieldName('username');
+ $query_1 .= 'B.*, U.'. $userservice->getFieldName('username')
+ . ', U.name';
$query_2 = ' FROM '. $userservice->getTableName() .' AS U'
. ', '. $this->getTableName() .' AS B';
@@ -745,7 +756,7 @@ class SemanticScuttle_Service_Bookmark extends SemanticScuttle_DbService
$arrWatch = $userservice->getWatchlist($user);
if (count($arrWatch) > 0) {
$query_3_1 = '';
- foreach($arrWatch as $row) {
+ foreach ($arrWatch as $row) {
$query_3_1 .= 'B.uId = '. intval($row) .' OR ';
}
$query_3_1 = substr($query_3_1, 0, -3);
@@ -756,7 +767,7 @@ class SemanticScuttle_Service_Bookmark extends SemanticScuttle_DbService
}
$query_5 = '';
- if($hash == null) {
+ if ($hash == null) {
$query_5.= ' GROUP BY B.bHash';
}
@@ -804,7 +815,9 @@ class SemanticScuttle_Service_Bookmark extends SemanticScuttle_DbService
$query_2 .= ', '. $b2tservice->getTableName() .' AS T'. $i;
$query_4 .= ' AND (';
- $allLinkedTags = $tag2tagservice->getAllLinkedTags($this->db->sql_escape($tags[$i]), '>', $user);
+ $allLinkedTags = $tag2tagservice->getAllLinkedTags(
+ $this->db->sql_escape($tags[$i]), '>', $user
+ );
while (is_array($allLinkedTags) && count($allLinkedTags)>0) {
$query_4 .= ' T'. $i .'.tag = "'. array_pop($allLinkedTags) .'"';
@@ -825,7 +838,8 @@ class SemanticScuttle_Service_Bookmark extends SemanticScuttle_DbService
// Search terms in tags as well when none given
if (!count($tags)) {
- $query_2 .= ' LEFT JOIN '. $b2tservice->getTableName() .' AS T ON B.bId = T.bId';
+ $query_2 .= ' LEFT JOIN '. $b2tservice->getTableName() .' AS T'
+ . ' ON B.bId = T.bId';
$dotags = true;
} else {
$dotags = false;
@@ -833,12 +847,24 @@ class SemanticScuttle_Service_Bookmark extends SemanticScuttle_DbService
$query_4 = '';
for ($i = 0; $i < count($aTerms); $i++) {
- $query_4 .= ' AND (B.bTitle LIKE "%'. $this->db->sql_escape($aTerms[$i]) .'%"';
- $query_4 .= ' OR B.bDescription LIKE "%'. $this->db->sql_escape($aTerms[$i]) .'%"';
- $query_4 .= ' OR B.bPrivateNote LIKE "'. $this->db->sql_escape($aTerms[$i]) .'%"'; //warning : search in private notes of everybody but private notes won't appear if not allowed.
- $query_4 .= ' OR U.username = "'. $this->db->sql_escape($aTerms[$i]) .'"'; //exact match for username
+ $query_4 .= ' AND (B.bTitle LIKE "%'
+ . $this->db->sql_escape($aTerms[$i])
+ . '%"';
+ $query_4 .= ' OR B.bDescription LIKE "%'
+ . $this->db->sql_escape($aTerms[$i])
+ . '%"';
+ //warning : search in private notes of everybody
+ // but private notes won't appear if not allowed.
+ $query_4 .= ' OR B.bPrivateNote LIKE "'
+ . $this->db->sql_escape($aTerms[$i])
+ .'%"';
+ $query_4 .= ' OR U.username = "'
+ . $this->db->sql_escape($aTerms[$i])
+ . '"'; //exact match for username
if ($dotags) {
- $query_4 .= ' OR T.tag LIKE "'. $this->db->sql_escape($aTerms[$i]) .'%"';
+ $query_4 .= ' OR T.tag LIKE "'
+ . $this->db->sql_escape($aTerms[$i])
+ . '%"';
}
$query_4 .= ')';
}
@@ -860,22 +886,35 @@ class SemanticScuttle_Service_Bookmark extends SemanticScuttle_DbService
$query = $query_1 . $query_2 . $query_3 . $query_4 . $query_5;
- if (!($dbresult = & $this->db->sql_query_limit($query, intval($perpage), intval($start)))) {
- message_die(GENERAL_ERROR, 'Could not get bookmarks', '', __LINE__, __FILE__, $query, $this->db);
+ $dbresult = $this->db->sql_query_limit(
+ $query, intval($perpage), intval($start)
+ );
+ if (!$dbresult) {
+ message_die(
+ GENERAL_ERROR, 'Could not get bookmarks',
+ '', __LINE__, __FILE__, $query, $this->db
+ );
}
if (SQL_LAYER == 'mysql4') {
$totalquery = 'SELECT FOUND_ROWS() AS total';
} else {
if ($hash) {
- $totalquery = 'SELECT COUNT(*) AS total'. $query_2 . $query_3 . $query_4;
+ $totalquery = 'SELECT COUNT(*) AS total'. $query_2
+ . $query_3 . $query_4;
} else {
- $totalquery = 'SELECT COUNT(DISTINCT bAddress) AS total'. $query_2 . $query_3 . $query_4;
+ $totalquery = 'SELECT COUNT(DISTINCT bAddress) AS total'
+ . $query_2 . $query_3 . $query_4;
}
}
- if (!($totalresult = & $this->db->sql_query($totalquery)) || (!($row = & $this->db->sql_fetchrow($totalresult)))) {
- message_die(GENERAL_ERROR, 'Could not get total bookmarks', '', __LINE__, __FILE__, $totalquery, $this->db);
+ if (!($totalresult = $this->db->sql_query($totalquery))
+ || (!($row = $this->db->sql_fetchrow($totalresult)))
+ ) {
+ message_die(
+ GENERAL_ERROR, 'Could not get total bookmarks',
+ '', __LINE__, __FILE__, $totalquery, $this->db
+ );
}
$total = $row['total'];
@@ -962,10 +1001,14 @@ class SemanticScuttle_Service_Bookmark extends SemanticScuttle_DbService
*/
public function deleteBookmarksForUser($uId)
{
- $query = 'DELETE FROM '. $GLOBALS['tableprefix'] .'bookmarks WHERE uId = '. intval($uId);
+ $query = 'DELETE FROM '. $GLOBALS['tableprefix'] . 'bookmarks'
+ . ' WHERE uId = '. intval($uId);
- if (!($dbresult = & $this->db->sql_query($query))) {
- message_die(GENERAL_ERROR, 'Could not delete bookmarks', '', __LINE__, __FILE__, $query, $this->db);
+ if (!($dbresult = $this->db->sql_query($query))) {
+ message_die(
+ GENERAL_ERROR, 'Could not delete bookmarks',
+ '', __LINE__, __FILE__, $query, $this->db
+ );
}
return true;
@@ -977,12 +1020,6 @@ class SemanticScuttle_Service_Bookmark extends SemanticScuttle_DbService
* Counts the number of bookmarks that have the same address
* as the given address.
*
- * @internal
- * We do support fetching counts for multiple addresses at once
- * because that allows us to reduce the number of queries
- * we need in the web interface when displaying i.e.
- * 10 bookmarks - only one SQL query is needed then.
- *
* @param string|array $addresses Address/URL to look for, string
* of one address or array with
* multiple ones
@@ -991,6 +1028,12 @@ class SemanticScuttle_Service_Bookmark extends SemanticScuttle_DbService
* In case $addresses was an array, key-value array
* with key being the address, value said number of
* bookmarks
+ *
+ * @internal
+ * We do support fetching counts for multiple addresses at once
+ * because that allows us to reduce the number of queries
+ * we need in the web interface when displaying i.e.
+ * 10 bookmarks - only one SQL query is needed then.
*/
public function countOthers($addresses)
{
diff --git a/src/SemanticScuttle/Service/Bookmark2Tag.php b/src/SemanticScuttle/Service/Bookmark2Tag.php
index 4d2c969..a10cb61 100644
--- a/src/SemanticScuttle/Service/Bookmark2Tag.php
+++ b/src/SemanticScuttle/Service/Bookmark2Tag.php
@@ -454,58 +454,155 @@ class SemanticScuttle_Service_Bookmark2Tag extends SemanticScuttle_DbService
return $output;
}
- function &getAdminTags($limit = 30, $logged_on_user = NULL, $days = NULL) {
+
+
+ /**
+ * Returns the tags used by admin users
+ *
+ * @param integer $limit Number of tags to return
+ * @param integer $logged_on_user ID of the user that's currently logged in.
+ * If the logged in user equals the $user to find
+ * tags for, tags of private bookmarks are
+ * returned.
+ * @param integer $days Bookmarks have to be changed in the last X days
+ * if their tags shall count
+ * @param string $beginsWith The tag name shall begin with that string
+ *
+ * @return array Array of found tags. Each tag entry is an array with two keys,
+ * 'tag' (tag name) and 'bCount'.
+ *
+ * @see getPopularTags()
+ */
+ public function getAdminTags(
+ $limit = 30, $logged_on_user = null, $days = null, $beginsWith = null
+ ) {
// look for admin ids
- $userservice = SemanticScuttle_Service_Factory :: get('User');
- $adminIds = $userservice->getAdminIds();
+ $userservice = SemanticScuttle_Service_Factory::get('User');
+ $adminIds = $userservice->getAdminIds();
// ask for their tags
- return $this->getPopularTags($adminIds, $limit, $logged_on_user, $days);
+ return $this->getPopularTags(
+ $adminIds, $limit, $logged_on_user, $days, $beginsWith
+ );
}
- function &getContactTags($user, $limit = 30, $logged_on_user = NULL, $days = NULL) {
+
+
+
+ /**
+ * Returns the tags used by users that are part of the user's watchlist,
+ * and the current user's own tags.
+ *
+ * @param integer $user ID of the user to get the watchlist from
+ * @param integer $limit Number of tags to return
+ * @param integer $logged_on_user ID of the user that's currently logged in.
+ * If set, that user is added to the list of
+ * people to get the tags from
+ * @param integer $days Bookmarks have to be changed in the last X days
+ * if their tags shall count
+ * @param string $beginsWith The tag name shall begin with that string
+ *
+ * @return array Array of found tags. Each tag entry is an array with two keys,
+ * 'tag' (tag name) and 'bCount'.
+ *
+ * @see getPopularTags()
+ */
+ public function getContactTags(
+ $user, $limit = 30, $logged_on_user = null, $days = null,
+ $beginsWith = null
+ ) {
// look for contact ids
- $userservice = SemanticScuttle_Service_Factory :: get('User');
+ $userservice = SemanticScuttle_Service_Factory::get('User');
$contacts = $userservice->getWatchlist($user);
- // add the user (to show him/her also his/her tags)
- if(!is_null($logged_on_user)) {
+ // add the user (to show him also his own tags)
+ if (!is_null($logged_on_user)) {
$contacts[] = $logged_on_user;
}
// ask for their tags
- return $this->getPopularTags($contacts, $limit, $logged_on_user, $days);
+ return $this->getPopularTags(
+ $contacts, $limit, $logged_on_user, $days, $beginsWith
+ );
}
- // $users can be {NULL, an id, an array of id}
- function &getPopularTags($user = NULL, $limit = 30, $logged_on_user = NULL, $days = NULL) {
+
+
+ /**
+ * The the most popular tags and their usage count
+ *
+ * @param mixed $user Integer user ID or array of user IDs to limit tag
+ * finding to
+ * @param integer $limit Number of tags to return
+ * @param integer $logged_on_user ID of the user that's currently logged in.
+ * If the logged in user equals the $user to find
+ * tags for, tags of private bookmarks are
+ * returned.
+ * @param integer $days Bookmarks have to be changed in the last X days
+ * if their tags shall count
+ * @param string $beginsWith The tag name shall begin with that string
+ *
+ * @return array Array of found tags. Each tag entry is an array with two keys,
+ * 'tag' (tag name) and 'bCount'.
+ *
+ * @see getAdminTags()
+ * @see getContactTags()
+ */
+ public function getPopularTags(
+ $user = null, $limit = 30, $logged_on_user = null, $days = null,
+ $beginsWith = null
+ ) {
// Only count the tags that are visible to the current user.
- if (($user != $logged_on_user) || is_null($user) || ($user === false))
- $privacy = ' AND B.bStatus = 0';
- else
- $privacy = '';
+ if (($user != $logged_on_user) || is_null($user) || ($user === false)) {
+ $privacy = ' AND B.bStatus = 0';
+ } else {
+ $privacy = '';
+ }
- if (is_null($days) || !is_int($days))
- $span = '';
- else
- $span = ' AND B.bDatetime > "'. date('Y-m-d H:i:s', time() - (86400 * $days)) .'"';
+ $query = 'SELECT'
+ . ' T.tag, COUNT(T.bId) AS bCount'
+ . ' FROM '
+ . $this->getTableName() . ' AS T'
+ . ', ' . $GLOBALS['tableprefix'] . 'bookmarks AS B'
+ . ' WHERE';
- $query = 'SELECT T.tag, COUNT(T.bId) AS bCount FROM '. $this->getTableName() .' AS T, '. $GLOBALS['tableprefix'] .'bookmarks AS B WHERE ';
if (is_null($user) || ($user === false)) {
- $query .= 'B.bId = T.bId AND B.bStatus = 0';
- } elseif(is_array($user)) {
+ $query .= ' B.bId = T.bId AND B.bStatus = 0';
+ } else if (is_array($user)) {
$query .= ' (1 = 0'; //tricks
- foreach($user as $u) {
- $query .= ' OR B.uId = '. $this->db->sql_escape($u) .' AND B.bId = T.bId';
+ foreach ($user as $u) {
+ if (is_numeric($u)) {
+ $query .= ' OR B.uId = ' . $this->db->sql_escape($u)
+ . ' AND B.bId = T.bId';
+ }
}
- $query .= ' )';
+ $query .= ' )' . $privacy;
} else {
- $query .= 'B.uId = '. $this->db->sql_escape($user) .' AND B.bId = T.bId'. $privacy;
+ $query .= ' B.uId = ' . $this->db->sql_escape($user)
+ . ' AND B.bId = T.bId' . $privacy;
}
- $query .= $span .' AND LEFT(T.tag, 7) <> "system:" GROUP BY T.tag ORDER BY bCount DESC, tag';
- if (!($dbresult =& $this->db->sql_query_limit($query, $limit))) {
- message_die(GENERAL_ERROR, 'Could not get popular tags', '', __LINE__, __FILE__, $query, $this->db);
+ if (is_int($days)) {
+ $query .= ' AND B.bDatetime > "'
+ . date('Y-m-d H:i:s', time() - (86400 * $days))
+ . '"';
+ }
+
+ if (!is_null($beginsWith)) {
+ $query .= ' AND T.tag LIKE \''
+ . $this->db->sql_escape($beginsWith)
+ . '%\'';
+ }
+
+ $query .= ' AND LEFT(T.tag, 7) <> "system:"'
+ . ' GROUP BY T.tag'
+ . ' ORDER BY bCount DESC, tag';
+
+ if (!($dbresult = $this->db->sql_query_limit($query, $limit))) {
+ message_die(
+ GENERAL_ERROR, 'Could not get popular tags',
+ '', __LINE__, __FILE__, $query, $this->db
+ );
return false;
}
@@ -514,6 +611,8 @@ class SemanticScuttle_Service_Bookmark2Tag extends SemanticScuttle_DbService
return $output;
}
+
+
function hasTag($bookmarkid, $tag) {
$query = 'SELECT COUNT(*) AS tCount FROM '. $this->getTableName() .' WHERE bId = '. intval($bookmarkid) .' AND tag ="'. $this->db->sql_escape($tag) .'"';
@@ -592,7 +691,15 @@ class SemanticScuttle_Service_Bookmark2Tag extends SemanticScuttle_DbService
return $output;
}
- function deleteAll() {
+
+
+ /**
+ * Deletes all tags in bookmarks2tags
+ *
+ * @return void
+ */
+ public function deleteAll()
+ {
$query = 'TRUNCATE TABLE `'. $this->getTableName() .'`';
$this->db->sql_query($query);
}
diff --git a/src/SemanticScuttle/Service/SearchHistory.php b/src/SemanticScuttle/Service/SearchHistory.php
index df9b256..a056ce2 100644
--- a/src/SemanticScuttle/Service/SearchHistory.php
+++ b/src/SemanticScuttle/Service/SearchHistory.php
@@ -26,7 +26,18 @@
*/
class SemanticScuttle_Service_SearchHistory extends SemanticScuttle_DbService
{
- var $sizeSearchHistory;
+ /**
+ * Size of the search history.
+ * If the number of logged searches is larger than this,
+ * adding a new search will delete the oldest one automatically.
+ *
+ * Use -1 to deactivate automatic deletion.
+ *
+ * @var integer
+ */
+ public $sizeSearchHistory;
+
+
/**
* Returns the single service instance
@@ -44,109 +55,223 @@ class SemanticScuttle_Service_SearchHistory extends SemanticScuttle_DbService
return $instance;
}
+
+
+ /**
+ * Creates a new instance.
+ *
+ * Sets $this->sizeSearchHistory to $GLOBALS['sizeSearchHistory'] or 10
+ * if the global variable is not defined.
+ *
+ * @param DB $db Database object
+ */
public function __construct($db)
{
$this->db = $db;
- $this->tablename = $GLOBALS['tableprefix'] .'searchhistory';
- if(isset($GLOBALS['sizeSearchHistory'])) {
+ $this->tablename = $GLOBALS['tableprefix'] . 'searchhistory';
+ if (isset($GLOBALS['sizeSearchHistory'])) {
$this->sizeSearchHistory = $GLOBALS['sizeSearchHistory'];
} else {
$this->sizeSearchHistory = 10;
}
}
- function addSearch($terms, $range, $nbResults, $uId=0) {
- if(strlen($terms) == 0) {
+
+
+ /**
+ * Adds a new search to the search history.
+ * Automatically deletes the oldest search when the number of
+ * searches is larger than $sizeSearchHistory.
+ *
+ * @param string $terms Search terms separated by spaces
+ * @param string $range - 'all' - search was in all bookmarks
+ * - 'watchlist' - searched in watchlist
+ * - any username to show that the search happened
+ * in his own bookmarks.
+ * @param integer $nbResults Number of search result rows
+ * @param integer $uId ID of user that searched
+ *
+ * @return boolean True if it has been added, false if not
+ */
+ public function addSearch($terms, $range, $nbResults, $uId = 0)
+ {
+ if (strlen($terms) == 0) {
return false;
}
$datetime = gmdate('Y-m-d H:i:s', time());
//Insert values
- $values = array('shTerms'=>$terms, 'shRange'=>$range, 'shDatetime'=>$datetime, 'shNbResults'=>$nbResults, 'uId'=>$uId);
- $sql = 'INSERT INTO '. $this->getTableName() .' '. $this->db->sql_build_array('INSERT', $values);
+ $values = array(
+ 'shTerms' => $terms,
+ 'shRange' => $range,
+ 'shDatetime' => $datetime,
+ 'shNbResults' => $nbResults,
+ 'uId' => $uId
+ );
+ $sql = 'INSERT INTO ' . $this->getTableName()
+ . ' ' . $this->db->sql_build_array('INSERT', $values);
+
$this->db->sql_transaction('begin');
- if (!($dbresult = & $this->db->sql_query($sql))) {
+ if (!($dbresult = $this->db->sql_query($sql))) {
$this->db->sql_transaction('rollback');
- message_die(GENERAL_ERROR, 'Could not insert search history', '', __LINE__, __FILE__, $sql, $this->db);
+ message_die(
+ GENERAL_ERROR, 'Could not insert search history',
+ '', __LINE__, __FILE__, $sql, $this->db
+ );
return false;
}
- if($this->sizeSearchHistory != -1 &&
- $this->countSearches() > $this->sizeSearchHistory) {
+ if ($this->sizeSearchHistory != -1
+ && $this->countSearches() > $this->sizeSearchHistory
+ ) {
$this->deleteOldestSearch();
}
+
+ return true;
}
- function getAllSearches($range = NULL, $uId = NULL, $nb = NULL, $start = NULL, $distinct = false, $withResults = false) {
- $sql = 'SELECT DISTINCT(shTerms), shId, shRange, shNbResults, shDatetime, uId';
+
+
+ /**
+ * Returns searches with the given features.
+ *
+ * @param string $range - 'all' - search was in all bookmarks
+ * - 'watchlist' - searched in watchlist
+ * - any username to show that the search happened
+ * in his own bookmarks.
+ * @param integer $uId Id of the user who searched. null for any users
+ * @param integer $nb Number of bookmarks to retrieve (paging)
+ * @param integer $start Number of bookmark to begin with (paging)
+ * @param boolean $distinct If the search terms shall be distinct
+ * @param boolean $withResults Only return searches that had at least one result
+ *
+ * @return array Array of search history database rows
+ */
+ public function getAllSearches(
+ $range = null, $uId = null, $nb = null,
+ $start = null, $distinct = false, $withResults = false
+ ) {
+ $sql = 'SELECT DISTINCT(shTerms),'
+ . ' shId, shRange, shNbResults, shDatetime, uId';
$sql.= ' FROM '. $this->getTableName();
$sql.= ' WHERE 1=1';
- if($range != NULL) {
+ if ($range != null) {
$sql.= ' AND shRange = "'.$range.'"';
} else {
$sql.= ' AND shRange = "all"';
}
- if($uId != NULL) {
+ if ($uId != null) {
$sql.= ' AND uId = '.$uId;
}
- if($withResults = true) {
+ if ($withResults == true) {
$sql.= ' AND shNbResults > 0';
}
- if($distinct) {
+ if ($distinct) {
$sql.= ' GROUP BY shTerms';
}
$sql.= ' ORDER BY shId DESC';
- if (!($dbresult = & $this->db->sql_query_limit($sql, $nb, $start))) {
- message_die(GENERAL_ERROR, 'Could not get searches', '', __LINE__, __FILE__, $sql, $this->db);
+ if (!($dbresult = $this->db->sql_query_limit($sql, $nb, $start))) {
+ message_die(
+ GENERAL_ERROR, 'Could not get searches',
+ '', __LINE__, __FILE__, $sql, $this->db
+ );
return false;
}
$searches = array();
- while ($row = & $this->db->sql_fetchrow($dbresult)) {
+ while ($row = $this->db->sql_fetchrow($dbresult)) {
$searches[] = $row;
}
$this->db->sql_freeresult($dbresult);
return $searches;
}
- function countSearches() {
+
+
+ /**
+ * Counts the number of searches that have been made in total.
+ *
+ * @return integer Number of searches
+ */
+ public function countSearches()
+ {
$sql = 'SELECT COUNT(*) AS `total` FROM '. $this->getTableName();
- if (!($dbresult = & $this->db->sql_query($sql)) || (!($row = & $this->db->sql_fetchrow($dbresult)))) {
- message_die(GENERAL_ERROR, 'Could not get total searches', '', __LINE__, __FILE__, $sql, $this->db);
+ if (!($dbresult = $this->db->sql_query($sql))
+ || (!($row = & $this->db->sql_fetchrow($dbresult)))
+ ) {
+ message_die(
+ GENERAL_ERROR, 'Could not get total searches',
+ '', __LINE__, __FILE__, $sql, $this->db
+ );
return false;
}
$this->db->sql_freeresult($dbresult);
return $row['total'];
}
- /* This function allows to limit the number of saved searches
- by deleting the oldest one */
- function deleteOldestSearch() {
+
+
+ /**
+ * This function allows to limit the number of saved searches
+ * by deleting the oldest one
+ *
+ * @return boolean True when all went well, false in case of an error
+ */
+ public function deleteOldestSearch()
+ {
$sql = 'DELETE FROM '.$this->getTableName();
- $sql.= ' ORDER BY shId ASC LIMIT 1'; // warning: here the limit is important
+ // warning: here the limit is important
+ $sql .= ' ORDER BY shId ASC LIMIT 1';
$this->db->sql_transaction('begin');
- if (!($dbresult = & $this->db->sql_query($sql))) {
+ if (!($dbresult = $this->db->sql_query($sql))) {
$this->db->sql_transaction('rollback');
- message_die(GENERAL_ERROR, 'Could not delete bookmarks', '', __LINE__, __FILE__, $query, $this->db);
+ message_die(
+ GENERAL_ERROR, 'Could not delete bookmarks',
+ '', __LINE__, __FILE__, $query, $this->db
+ );
return false;
}
+
+ return true;
}
- function deleteSearchHistoryForUser($uId) {
- $query = 'DELETE FROM '. $this->getTableName() .' WHERE uId = '. intval($uId);
- if (!($dbresult = & $this->db->sql_query($query))) {
- message_die(GENERAL_ERROR, 'Could not delete search history', '',
- __LINE__, __FILE__, $query, $this->db);
+
+ /**
+ * Deletes all search history entries that have been made by the user
+ * with the given ID.
+ *
+ * @param integer $uId ID of the user
+ *
+ * @return boolean True when all went well, false in case of an error
+ */
+ public function deleteSearchHistoryForUser($uId)
+ {
+ $query = 'DELETE FROM '. $this->getTableName()
+ . ' WHERE uId = ' . intval($uId);
+
+ if (!($dbresult = $this->db->sql_query($query))) {
+ message_die(
+ GENERAL_ERROR, 'Could not delete search history', '',
+ __LINE__, __FILE__, $query, $this->db
+ );
return false;
}
return true;
}
- function deleteAll() {
+
+
+ /**
+ * Deletes all search history entries.
+ *
+ * @return void
+ */
+ public function deleteAll()
+ {
$query = 'TRUNCATE TABLE `'. $this->getTableName() .'`';
$this->db->sql_query($query);
}
diff --git a/src/SemanticScuttle/Service/Tag2Tag.php b/src/SemanticScuttle/Service/Tag2Tag.php
index 8666209..33d211b 100644
--- a/src/SemanticScuttle/Service/Tag2Tag.php
+++ b/src/SemanticScuttle/Service/Tag2Tag.php
@@ -14,7 +14,7 @@
*/
/**
- * SemanticScuttle tag-to-tag service.
+ * SemanticScuttle tag-to-tag service which works with tag relations.
*
* @category Bookmarking
* @package SemanticScuttle
@@ -102,18 +102,49 @@ class SemanticScuttle_Service_Tag2Tag extends SemanticScuttle_DbService
return true;
}
- // Return linked tags just for admin users
- function getAdminLinkedTags($tag, $relationType, $inverseRelation = false, $stopList = array()) {
+
+
+ /**
+ * Same as getLinkedTags(), but only tags that have been created
+ * by admin users are returned.
+ *
+ * @param string $tag Tag to get related tags for
+ * @param string $relationType Type of tag-to-tag relation: >, < or =
+ * @param boolean $inverseRelation Reverse relation (parent -> child)
+ * @param array $stopList Array of tags that shall not be returned
+ *
+ * @return array Array of tag names
+ *
+ * @see getLinkedTags()
+ */
+ public function getAdminLinkedTags(
+ $tag, $relationType, $inverseRelation = false, $stopList = array()
+ ) {
// look for admin ids
$userservice = SemanticScuttle_Service_Factory :: get('User');
- $adminIds = $userservice->getAdminIds();
+ $adminIds = $userservice->getAdminIds();
//ask for their linked tags
- return $this->getLinkedTags($tag, $relationType, $adminIds, $inverseRelation, $stopList);
+ return $this->getLinkedTags(
+ $tag, $relationType, $adminIds, $inverseRelation, $stopList
+ );
}
- // Return the target linked tags. If inverseRelation is true, return the source linked tags.
- function getLinkedTags($tag, $relationType, $uId = null, $inverseRelation = false, $stopList = array()) {
+
+
+ /**
+ * Returns an array of tags that are in relation to the given $tag.
+ *
+ * @param string $tag Tag to get related tags for
+ * @param string $relationType Type of tag-to-tag relation: >, < or =
+ * @param boolean $inverseRelation Reverse relation (parent -> child)
+ * @param array $stopList Array of tags that shall not be returned
+ *
+ * @return array Array of tag names
+ */
+ public function getLinkedTags(
+ $tag, $relationType, $uId = null, $inverseRelation = false, $stopList = array()
+ ) {
// Set up the SQL query.
if($inverseRelation) {
$queriedTag = "tag1";
diff --git a/src/SemanticScuttle/Service/User.php b/src/SemanticScuttle/Service/User.php
index b92abc6..5fee21d 100644
--- a/src/SemanticScuttle/Service/User.php
+++ b/src/SemanticScuttle/Service/User.php
@@ -211,18 +211,26 @@ class SemanticScuttle_Service_User extends SemanticScuttle_DbService
}
}
- /* Takes an numerical "id" or a string "username"
- and returns the numerical "id" if the user exists else returns NULL */
- function getIdFromUser($user) {
+ /**
+ * Obtains the ID of the given user name.
+ * If a user ID is passed, it is returned.
+ * In case the user does not exist, NULL is returned.
+ *
+ * @param string|integer $user User name or user ID
+ *
+ * @return integer NULL if not found or the user ID
+ */
+ public function getIdFromUser($user)
+ {
if (is_int($user)) {
return intval($user);
} else {
$objectUser = $this->getObjectUserByUsername($user);
- if($objectUser != NULL) {
+ if ($objectUser != null) {
return $objectUser->getId();
}
}
- return NULL;
+ return null;
}
/**
@@ -404,10 +412,10 @@ class SemanticScuttle_Service_User extends SemanticScuttle_DbService
public function getCurrentUserId()
{
if (isset($_SESSION[$this->getSessionKey()])) {
- return $_SESSION[$this->getSessionKey()];
+ return (int)$_SESSION[$this->getSessionKey()];
} else if (isset($_COOKIE[$this->getCookieKey()])) {
- $cook = split(':', $_COOKIE[$this->getCookieKey()]);
+ $cook = explode(':', $_COOKIE[$this->getCookieKey()]);
//cookie looks like this: 'id:md5(username+password)'
$query = 'SELECT * FROM '. $this->getTableName() .
' WHERE MD5(CONCAT('.$this->getFieldName('username') .
@@ -425,10 +433,10 @@ class SemanticScuttle_Service_User extends SemanticScuttle_DbService
if ($row = $this->db->sql_fetchrow($dbresult)) {
$this->setCurrentUserId(
- $row[$this->getFieldName('primary')]
+ (int)$row[$this->getFieldName('primary')]
);
$this->db->sql_freeresult($dbresult);
- return $_SESSION[$this->getSessionKey()];
+ return (int)$_SESSION[$this->getSessionKey()];
}
}
return false;
@@ -716,7 +724,7 @@ class SemanticScuttle_Service_User extends SemanticScuttle_DbService
}
/**
- * Delete all bookmarks.
+ * Delete all users and their watch states.
* Mainly used in unit tests.
*
* @return void
@@ -725,6 +733,9 @@ class SemanticScuttle_Service_User extends SemanticScuttle_DbService
{
$query = 'TRUNCATE TABLE `'. $this->getTableName() .'`';
$this->db->sql_query($query);
+
+ $query = 'TRUNCATE TABLE `' . $GLOBALS['tableprefix'] . 'watched' . '`';
+ $this->db->sql_query($query);
}
/**
diff --git a/src/SemanticScuttle/constants.php b/src/SemanticScuttle/constants.php
index 95c4384..b023840 100644
--- a/src/SemanticScuttle/constants.php
+++ b/src/SemanticScuttle/constants.php
@@ -1,34 +1,51 @@
<?php
-/*
+/**
* Define constants used in all the application.
* Some constants are based on variables from configuration file.
+ *
+ * SemanticScuttle - your social bookmark manager.
+ *
+ * PHP version 5.
+ *
+ * @category Bookmarking
+ * @package SemanticScuttle
+ * @subcategory Base
+ * @author Benjamin Huynh-Kim-Bang <mensonge@users.sourceforge.net>
+ * @author Christian Weiske <cweiske@cweiske.de>
+ * @author Eric Dane <ericdane@users.sourceforge.net>
+ * @license GPL http://www.gnu.org/licenses/gpl.html
+ * @link http://sourceforge.net/projects/semanticscuttle
*/
// Debug managament
-if(isset($GLOBALS['debugMode'])) {
- define('DEBUG_MODE', $GLOBALS['debugMode']);
- define('DEBUG_EXTRA', $GLOBALS['debugMode']); // Constant used exclusively into db/ directory
+if (isset($GLOBALS['debugMode'])) {
+ define('DEBUG_MODE', $GLOBALS['debugMode']);
+ // Constant used exclusively into db/ directory
+ define('DEBUG_EXTRA', $GLOBALS['debugMode']);
}
// Determine the base URL as ROOT
if (!isset($GLOBALS['root'])) {
- $pieces = explode('/', $_SERVER['SCRIPT_NAME']);
-
- $rootTmp = '/';
- foreach ($pieces as $piece) {
- //we eliminate possible sscuttle subfolders (like gsearch for example)
- if ($piece != '' && !strstr($piece, '.php') && $piece != 'gsearch') {
- $rootTmp .= $piece .'/';
- }
- }
- if (($rootTmp != '/') && (substr($rootTmp, -1, 1) != '/')) {
- $rootTmp .= '/';
- }
-
- define('ROOT', 'http://'. $_SERVER['HTTP_HOST'] . $rootTmp);
+ $pieces = explode('/', $_SERVER['SCRIPT_NAME']);
+
+ $rootTmp = '/';
+ foreach ($pieces as $piece) {
+ //we eliminate possible sscuttle subfolders (like gsearch for example)
+ if ($piece != '' && !strstr($piece, '.php')
+ && $piece != 'gsearch' && $piece != 'ajax'
+ ) {
+ $rootTmp .= $piece .'/';
+ }
+ }
+ if (($rootTmp != '/') && (substr($rootTmp, -1, 1) != '/')) {
+ $rootTmp .= '/';
+ }
+
+ define('ROOT', 'http://'. $_SERVER['HTTP_HOST'] . $rootTmp);
} else {
- define('ROOT', $GLOBALS['root']);
+ define('ROOT', $GLOBALS['root']);
}
+define('ROOT_JS', ROOT . 'js/jstree-1.0-rc2/');
// Error codes
define('GENERAL_MESSAGE', 200);
@@ -44,19 +61,21 @@ define('PAGE_WATCHLIST', "watchlist");
// Miscellanous
-// INSTALLATION_ID is based on directory DB and used as prefix (in session and cookie) to prevent mutual login for different installations on the same host server
+// INSTALLATION_ID is based on directory DB and used as prefix
+// (in session and cookie) to prevent mutual login for different
+// installations on the same host server
define('INSTALLATION_ID', md5($GLOBALS['dbname'].$GLOBALS['tableprefix']));
// Correct bugs with PATH_INFO (maybe for Apache 1 or CGI) -- for 1&1 host...
if (isset($_SERVER['PATH_INFO']) && isset($_SERVER['ORIG_PATH_INFO'])) {
- if(strlen($_SERVER["PATH_INFO"])<strlen($_SERVER["ORIG_PATH_INFO"])) {
- $_SERVER["PATH_INFO"] = $_SERVER["ORIG_PATH_INFO"];
- }
- if(strcasecmp($_SERVER["PATH_INFO"], $_SERVER["SCRIPT_NAME "]) == 0) {
- unset($_SERVER["PATH_INFO"]);
- }
- if(strpos($_SERVER["PATH_INFO"], '.php') !== false) {
- unset($_SERVER["PATH_INFO"]);
- }
+ if (strlen($_SERVER["PATH_INFO"])<strlen($_SERVER["ORIG_PATH_INFO"])) {
+ $_SERVER["PATH_INFO"] = $_SERVER["ORIG_PATH_INFO"];
+ }
+ if (strcasecmp($_SERVER["PATH_INFO"], $_SERVER["SCRIPT_NAME "]) == 0) {
+ unset($_SERVER["PATH_INFO"]);
+ }
+ if (strpos($_SERVER["PATH_INFO"], '.php') !== false) {
+ unset($_SERVER["PATH_INFO"]);
+ }
}
?>
diff --git a/src/SemanticScuttle/db/mysqli.php b/src/SemanticScuttle/db/mysqli.php
index 03b36ea..9a2709a 100644
--- a/src/SemanticScuttle/db/mysqli.php
+++ b/src/SemanticScuttle/db/mysqli.php
@@ -50,7 +50,7 @@ class sql_db
}
}
- return $this->sql_error('');
+ return $this->sql_error(mysqli_connect_error());
}
//
diff --git a/src/SemanticScuttle/header.php b/src/SemanticScuttle/header.php
index 8939b60..75e5204 100644
--- a/src/SemanticScuttle/header.php
+++ b/src/SemanticScuttle/header.php
@@ -14,9 +14,21 @@
* @license GPL http://www.gnu.org/licenses/gpl.html
* @link http://sourceforge.net/projects/semanticscuttle
*/
-if (!file_exists(dirname(__FILE__) .'/../../data/config.php')) {
+
+if ('@data_dir@' == '@' . 'data_dir@') {
+ //non pear-install
+ $datadir = dirname(__FILE__) . '/../../data/';
+} else {
+ //pear installation; files are in include path
+ $datadir = '@data_dir@/SemanticScuttle/';
+}
+
+if (!file_exists($datadir . '/config.php')) {
header('HTTP/1.0 500 Internal Server Error');
- die('Please copy "config.php.dist" to "config.php" in data/ folder.');
+ die(
+ 'Please copy "config.php.dist" to "config.php" in data/ folder.'
+ . "\n"
+ );
}
set_include_path(
get_include_path() . PATH_SEPARATOR
@@ -24,10 +36,23 @@ set_include_path(
);
// 1 // First requirements part (before debug management)
-$datadir = dirname(__FILE__) . '/../../data/';
require_once $datadir . '/config.default.php';
require_once $datadir . '/config.php';
+if (isset($_GET['unittestMode']) && $_GET['unittestMode'] == 1
+) {
+ if ($allowUnittestMode !== true) {
+ header('HTTP/1.0 400 Bad Request');
+ die("Unittestmode is not allowed\n");
+ }
+
+ $unittestConfigFile = $datadir . '/config.unittest.php';
+ if (file_exists($unittestConfigFile)) {
+ require_once $unittestConfigFile;
+ }
+ define('HTTP_UNIT_TEST_MODE', true);
+ define('UNIT_TEST_MODE', true);
+}
if (defined('UNIT_TEST_MODE')) {
//make local config vars global - needed for unit tests
//run with phpunit
@@ -57,6 +82,7 @@ require_once 'SemanticScuttle/Service.php';
require_once 'SemanticScuttle/DbService.php';
require_once 'SemanticScuttle/Service/Factory.php';
require_once 'SemanticScuttle/functions.php';
+require_once 'SemanticScuttle/Model/UserArray.php';
if (count($GLOBALS['serviceoverrides']) > 0
&& !defined('UNIT_TEST_MODE')
@@ -106,11 +132,18 @@ $tplVars['currentUser'] = $currentUser;
$tplVars['userservice'] = $userservice;
// 6 // Force UTF-8 behaviour for server (cannot be moved into top.inc.php which is not included into every file)
-if (!defined('UNIT_TEST_MODE')) {
+if (!defined('UNIT_TEST_MODE') || defined('HTTP_UNIT_TEST_MODE')) {
//API files define that, so we need a way to support both of them
if (!isset($httpContentType)) {
- $httpContentType = 'text/html';
- //$httpContentType = 'application/xhtml+xml';
+ if (DEBUG_MODE) {
+ //using that mime type makes all javascript nice in Chromium
+ // it also serves as test base if the pages really validate
+ $httpContentType = 'application/xhtml+xml';
+ } else {
+ //until we are sure that all pages validate, we
+ // keep the non-strict mode on for normal installations
+ $httpContentType = 'text/html';
+ }
}
if ($httpContentType !== false) {
header('Content-Type: ' . $httpContentType . '; charset=utf-8');
diff --git a/src/php-gettext/Makefile b/src/php-gettext/Makefile
index 2dba911..a6cce12 100644
--- a/src/php-gettext/Makefile
+++ b/src/php-gettext/Makefile
@@ -1,12 +1,11 @@
PACKAGE = php-gettext-$(VERSION)
-VERSION = 1.0.7
+VERSION = 1.0.10
DIST_FILES = \
gettext.php \
gettext.inc \
streams.php \
AUTHORS \
- ChangeLog \
README \
COPYING \
Makefile \
@@ -17,9 +16,14 @@ DIST_FILES = \
examples/locale/sr_CS/LC_MESSAGES/messages.mo \
examples/locale/de_CH/LC_MESSAGES/messages.po \
examples/locale/de_CH/LC_MESSAGES/messages.mo \
- examples/update
+ examples/update \
+ tests/LocalesTest.php \
+ tests/ParsingTest.php
-dist:
+check:
+ phpunit --verbose tests
+
+dist: check
if [ -d $(PACKAGE) ]; then \
rm -rf $(PACKAGE); \
fi; \
@@ -30,3 +34,5 @@ dist:
rm -rf $(PACKAGE); \
fi;
+clean:
+ rm -f $(PACKAGE).tar.gz
diff --git a/src/php-gettext/README b/src/php-gettext/README
index c7525e2..bca4f91 100644
--- a/src/php-gettext/README
+++ b/src/php-gettext/README
@@ -1,9 +1,9 @@
-PHP-gettext 1.0
+PHP-gettext 1.0 (https://launchpad.net/php-gettext)
-Copyright 2003, 2006 -- Danilo "angry with PHP[1]" Segan
+Copyright 2003, 2006, 2009 -- Danilo "angry with PHP[1]" Segan
Licensed under GPLv2 (or any later version, see COPYING)
-[1] PHP is actually cyrillic, and translates roughly to
+[1] PHP is actually cyrillic, and translates roughly to
"works-doesn't-work" (UTF-8: Ради-Не-Ради)
@@ -50,36 +50,16 @@ Features
file data, I used imaginary abstract class StreamReader to do all
the input (check streams.php). For your convenience, I've already
provided two classes for reading files: FileReader and
- StringReader (CachedFileReader is a combination of the two: it
- loads entire file contents into a string, and then works on that).
- See example below for usage. You can for instance use StringReader
- when you read in data from a database, or you can create your own
- derivative of StreamReader for anything you like.
-
+ StringReader (CachedFileReader is a combination of the two: it
+ loads entire file contents into a string, and then works on that).
+ See example below for usage. You can for instance use StringReader
+ when you read in data from a database, or you can create your own
+ derivative of StreamReader for anything you like.
-Bugs
-
- Plural-forms field in MO header (translation for empty string,
- i.e. "") is treated according to PHP syntactic rules (it's
- eval()ed). Since these should actually follow C syntax, there are
- some problems.
- For instance, I'm used to using this:
- Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : \
- n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;
- but it fails with PHP (it sets $plural=2 instead of 0 for $n==1).
-
- The fix is usually simple, but I'm lazy to go into the details of
- PHP operator precedence, and maybe try to fix it. In here, I had
- to put everything after the first ':' in parenthesis:
- Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : \
- (n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);
- That works, and I'm satisfied.
+Bugs
- Besides this one, there are probably a bunch of other bugs, since
- I hate PHP (did I mention it already? no? strange), and don't
- know it very well. So, feel free to fix any of those and report
- them back to me at <danilo@kvota.net>.
+ Report them on https://bugs.launchpad.net/php-gettext
Usage
@@ -94,19 +74,19 @@ Usage
Then, use that as a parameter to gettext_reader constructor:
$wohoo = new gettext_reader($streamer);
- If you want to disable pre-loading of entire message catalog in
- memory (if, for example, you have a multi-thousand message catalog
- which you'll use only occasionally), use "false" for second
+ If you want to disable pre-loading of entire message catalog in
+ memory (if, for example, you have a multi-thousand message catalog
+ which you'll use only occasionally), use "false" for second
parameter to gettext_reader constructor:
$wohoo = new gettext_reader($streamer, false);
From now on, you have all the benefits of gettext data at your
- disposal, so may run:
+ disposal, so may run:
print $wohoo->translate("This is a test");
print $wohoo->ngettext("%d bird", "%d birds", $birds);
You might need to pass parameter "-k" to xgettext to make it
- extract all the strings. In above example, try with
+ extract all the strings. In above example, try with
xgettext -ktranslate -kngettext:1,2 file.php
what should create messages.po which contains two messages for
translation.
@@ -118,8 +98,8 @@ Usage
Usage with gettext.inc (standard gettext interfaces emulation)
- Check example in examples/pig_dropin.php, basically you include
- gettext.inc and use all the standard gettext interfaces as
+ Check example in examples/pig_dropin.php, basically you include
+ gettext.inc and use all the standard gettext interfaces as
documented on:
http://www.php.net/gettext
@@ -137,20 +117,12 @@ Example
There is also simple "update" script that can be used to generate
POT file and to update the translation using msgmerge.
-Interesting TODO:
+TODO:
- o Try to parse "plural-forms" header field, and to follow C syntax
- rules. This won't be easy.
+ o Improve speed to be even more comparable to the native gettext
+ implementation.
-Boring TODO:
-
- o Learn PHP and fix bugs, slowness and other stuff resulting from
- my lack of knowledge (but *maybe*, it's not my knowledge that is
- bad, but PHP itself ;-).
-
- (This is mostly done thanks to Nico Kaiser.)
-
- o Try to use hash tables in MO files: with pre-loading, would it
+ o Try to use hash tables in MO files: with pre-loading, would it
be useful at all?
Never-asked-questions:
@@ -160,7 +132,7 @@ Never-asked-questions:
Well, it's quite simple. I consider that the first released thing
should be labeled "version 1" (first, right?). Zero is there to
- indicate that there's zero improvement and/or change compared to
+ indicate that there's zero improvement and/or change compared to
"version 1".
I plan to use version numbers 1.0.* for small bugfixes, and to
@@ -173,7 +145,7 @@ Never-asked-questions:
Mozart's 40th Symphony (there is one like that, right?).
o Can I...?
-
+
Yes, you can. This is free software (as in freedom, free speech),
and you might do whatever you wish with it, provided you do not
limit freedom of others (GPL).
diff --git a/src/php-gettext/examples/locale/sr_CS/LC_MESSAGES/messages.mo b/src/php-gettext/examples/locale/sr_CS/LC_MESSAGES/messages.mo
index 6ffccfd..497c883 100644
--- a/src/php-gettext/examples/locale/sr_CS/LC_MESSAGES/messages.mo
+++ b/src/php-gettext/examples/locale/sr_CS/LC_MESSAGES/messages.mo
Binary files differ
diff --git a/src/php-gettext/examples/locale/sr_CS/LC_MESSAGES/messages.po b/src/php-gettext/examples/locale/sr_CS/LC_MESSAGES/messages.po
index 7e620cc..e5da0e9 100644
--- a/src/php-gettext/examples/locale/sr_CS/LC_MESSAGES/messages.po
+++ b/src/php-gettext/examples/locale/sr_CS/LC_MESSAGES/messages.po
@@ -12,7 +12,8 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : (n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n"
+"Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && "
+"n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n"
#: pigs.php:19
msgid ""
diff --git a/src/php-gettext/examples/pigs_dropin.php b/src/php-gettext/examples/pigs_dropin.php
index edd2b0d..94fd850 100644
--- a/src/php-gettext/examples/pigs_dropin.php
+++ b/src/php-gettext/examples/pigs_dropin.php
@@ -1,6 +1,6 @@
<?php
/*
- Copyright (c) 2003,2004,2005 Danilo Segan <danilo@kvota.net>.
+ Copyright (c) 2003,2004,2005,2009 Danilo Segan <danilo@kvota.net>.
Copyright (c) 2005,2006 Steven Armstrong <sa@c-area.ch>
This file is part of PHP-gettext.
@@ -21,10 +21,12 @@
*/
+error_reporting(E_ALL | E_STRICT);
+
// define constants
-define(PROJECT_DIR, realpath('./'));
-define(LOCALE_DIR, PROJECT_DIR .'/locale');
-define(DEFAULT_LOCALE, 'en_US');
+define('PROJECT_DIR', realpath('./'));
+define('LOCALE_DIR', PROJECT_DIR .'/locale');
+define('DEFAULT_LOCALE', 'en_US');
require_once('../gettext.inc');
diff --git a/src/php-gettext/examples/pigs_fallback.php b/src/php-gettext/examples/pigs_fallback.php
index b50f752..353190d 100644
--- a/src/php-gettext/examples/pigs_fallback.php
+++ b/src/php-gettext/examples/pigs_fallback.php
@@ -1,6 +1,6 @@
<?php
/*
- Copyright (c) 2003,2004,2005 Danilo Segan <danilo@kvota.net>.
+ Copyright (c) 2003,2004,2005,2009 Danilo Segan <danilo@kvota.net>.
Copyright (c) 2005,2006 Steven Armstrong <sa@c-area.ch>
This file is part of PHP-gettext.
@@ -21,10 +21,12 @@
*/
+error_reporting(E_ALL | E_STRICT);
+
// define constants
-define(PROJECT_DIR, realpath('./'));
-define(LOCALE_DIR, PROJECT_DIR .'/locale');
-define(DEFAULT_LOCALE, 'en_US');
+define('PROJECT_DIR', realpath('./'));
+define('LOCALE_DIR', PROJECT_DIR .'/locale');
+define('DEFAULT_LOCALE', 'en_US');
require_once('../gettext.inc');
diff --git a/src/php-gettext/examples/update b/src/php-gettext/examples/update
index c8d8b61..76b4308 100644
--- a/src/php-gettext/examples/update
+++ b/src/php-gettext/examples/update
@@ -1,7 +1,7 @@
#!/bin/sh
TEMPLATE=pigs.pot
-xgettext -kT_ngettext:1,2 -kT_ -L PHP -o $TEMPLATE pigs.php
-if [ x$1 == 'x-p' ]; then
+xgettext -kT_ngettext:1,2 -kT_ -L PHP -o $TEMPLATE pigs_dropin.php
+if [ "x$1" = "x-p" ]; then
msgfmt --statistics $TEMPLATE
else
if [ -f $1.po ]; then
diff --git a/src/php-gettext/gettext.inc b/src/php-gettext/gettext.inc
index a67811f..399a0f2 100644
--- a/src/php-gettext/gettext.inc
+++ b/src/php-gettext/gettext.inc
@@ -1,9 +1,10 @@
<?php
/*
Copyright (c) 2005 Steven Armstrong <sa at c-area dot ch>
-
+ Copyright (c) 2009 Danilo Segan <danilo@kvota.net>
+
Drop in replacement for native gettext.
-
+
This file is part of PHP-gettext.
PHP-gettext is free software; you can redistribute it and/or modify
@@ -22,15 +23,22 @@
*/
/*
-LC_CTYPE 0
-LC_NUMERIC 1
-LC_TIME 2
-LC_COLLATE 3
-LC_MONETARY 4
-LC_MESSAGES 5
-LC_ALL 6
+LC_CTYPE 0
+LC_NUMERIC 1
+LC_TIME 2
+LC_COLLATE 3
+LC_MONETARY 4
+LC_MESSAGES 5
+LC_ALL 6
*/
+
+// LC_MESSAGES is not available if php-gettext is not loaded
+// while the other constants are already available from session extension.
+if (!defined('LC_MESSAGES')) {
+ define('LC_MESSAGES', 5);
+}
+
require('streams.php');
require('gettext.php');
@@ -44,29 +52,96 @@ $LC_CATEGORIES = array('LC_CTYPE', 'LC_NUMERIC', 'LC_TIME', 'LC_COLLATE', 'LC_MO
$EMULATEGETTEXT = 0;
$CURRENTLOCALE = '';
+/* Class to hold a single domain included in $text_domains. */
+class domain {
+ var $l10n;
+ var $path;
+ var $codeset;
+}
// Utility functions
/**
+ * Return a list of locales to try for any POSIX-style locale specification.
+ */
+function get_list_of_locales($locale) {
+ /* Figure out all possible locale names and start with the most
+ * specific ones. I.e. for sr_CS.UTF-8@latin, look through all of
+ * sr_CS.UTF-8@latin, sr_CS@latin, sr@latin, sr_CS.UTF-8, sr_CS, sr.
+ */
+ $locale_names = array();
+ $lang = NULL;
+ $country = NULL;
+ $charset = NULL;
+ $modifier = NULL;
+ if ($locale) {
+ if (preg_match("/^(?P<lang>[a-z]{2,3})" // language code
+ ."(?:_(?P<country>[A-Z]{2}))?" // country code
+ ."(?:\.(?P<charset>[-A-Za-z0-9_]+))?" // charset
+ ."(?:@(?P<modifier>[-A-Za-z0-9_]+))?$/", // @ modifier
+ $locale, $matches)) {
+
+ if (isset($matches["lang"])) $lang = $matches["lang"];
+ if (isset($matches["country"])) $country = $matches["country"];
+ if (isset($matches["charset"])) $charset = $matches["charset"];
+ if (isset($matches["modifier"])) $modifier = $matches["modifier"];
+
+ if ($modifier) {
+ if ($country) {
+ if ($charset)
+ array_push($locale_names, "${lang}_$country.$charset@$modifier");
+ array_push($locale_names, "${lang}_$country@$modifier");
+ } elseif ($charset)
+ array_push($locale_names, "${lang}.$charset@$modifier");
+ array_push($locale_names, "$lang@$modifier");
+ }
+ if ($country) {
+ if ($charset)
+ array_push($locale_names, "${lang}_$country.$charset");
+ array_push($locale_names, "${lang}_$country");
+ } elseif ($charset)
+ array_push($locale_names, "${lang}.$charset");
+ array_push($locale_names, $lang);
+ }
+
+ // If the locale name doesn't match POSIX style, just include it as-is.
+ if (!in_array($locale, $locale_names))
+ array_push($locale_names, $locale);
+ }
+ return $locale_names;
+}
+
+/**
* Utility function to get a StreamReader for the given text domain.
*/
function _get_reader($domain=null, $category=5, $enable_cache=true) {
- global $text_domains, $default_domain, $LC_CATEGORIES;
- if (!isset($domain)) $domain = $default_domain;
- if (!isset($text_domains[$domain]->l10n)) {
- // get the current locale
- $locale = _setlocale(LC_MESSAGES, 0);
- $p = isset($text_domains[$domain]->path) ? $text_domains[$domain]->path : './';
- $path = $p . "$locale/". $LC_CATEGORIES[$category] ."/$domain.mo";
- if (file_exists($path)) {
- $input = new FileReader($path);
- }
- else {
- $input = null;
- }
- $text_domains[$domain]->l10n = new gettext_reader($input, $enable_cache);
- }
- return $text_domains[$domain]->l10n;
+ global $text_domains, $default_domain, $LC_CATEGORIES;
+ if (!isset($domain)) $domain = $default_domain;
+ if (!isset($text_domains[$domain]->l10n)) {
+ // get the current locale
+ $locale = _setlocale(LC_MESSAGES, 0);
+ $bound_path = isset($text_domains[$domain]->path) ?
+ $text_domains[$domain]->path : './';
+ $subpath = $LC_CATEGORIES[$category] ."/$domain.mo";
+
+ $locale_names = get_list_of_locales($locale);
+ $input = null;
+ foreach ($locale_names as $locale) {
+ $full_path = $bound_path . $locale . "/" . $subpath;
+ if (file_exists($full_path)) {
+ $input = new FileReader($full_path);
+ break;
+ }
+ }
+
+ if (!array_key_exists($domain, $text_domains)) {
+ // Initialize an empty domain object.
+ $text_domains[$domain] = new domain();
+ }
+ $text_domains[$domain]->l10n = new gettext_reader($input,
+ $enable_cache);
+ }
+ return $text_domains[$domain]->l10n;
}
/**
@@ -80,8 +155,10 @@ function locale_emulation() {
/**
* Checks if the current locale is supported on this system.
*/
-function _check_locale() {
+function _check_locale_and_function($function=false) {
global $EMULATEGETTEXT;
+ if ($function and !function_exists($function))
+ return false;
return !$EMULATEGETTEXT;
}
@@ -89,56 +166,70 @@ function _check_locale() {
* Get the codeset for the given domain.
*/
function _get_codeset($domain=null) {
- global $text_domains, $default_domain, $LC_CATEGORIES;
- if (!isset($domain)) $domain = $default_domain;
- return (isset($text_domains[$domain]->codeset))? $text_domains[$domain]->codeset : ini_get('mbstring.internal_encoding');
+ global $text_domains, $default_domain, $LC_CATEGORIES;
+ if (!isset($domain)) $domain = $default_domain;
+ return (isset($text_domains[$domain]->codeset))? $text_domains[$domain]->codeset : ini_get('mbstring.internal_encoding');
}
/**
* Convert the given string to the encoding set by bind_textdomain_codeset.
*/
function _encode($text) {
- $source_encoding = mb_detect_encoding($text);
- $target_encoding = _get_codeset();
- if ($source_encoding != $target_encoding) {
- return mb_convert_encoding($text, $target_encoding, $source_encoding);
- }
- else {
- return $text;
- }
+ $source_encoding = mb_detect_encoding($text);
+ $target_encoding = _get_codeset();
+ if ($source_encoding != $target_encoding) {
+ return mb_convert_encoding($text, $target_encoding, $source_encoding);
+ }
+ else {
+ return $text;
+ }
}
-
-
// Custom implementation of the standard gettext related functions
/**
+ * Returns passed in $locale, or environment variable $LANG if $locale == ''.
+ */
+function _get_default_locale($locale) {
+ if ($locale == '') // emulate variable support
+ return getenv('LANG');
+ else
+ return $locale;
+}
+
+/**
* Sets a requested locale, if needed emulates it.
*/
function _setlocale($category, $locale) {
global $CURRENTLOCALE, $EMULATEGETTEXT;
if ($locale === 0) { // use === to differentiate between string "0"
- if ($CURRENTLOCALE != '')
+ if ($CURRENTLOCALE != '')
return $CURRENTLOCALE;
- else
+ else
// obey LANG variable, maybe extend to support all of LC_* vars
// even if we tried to read locale without setting it first
return _setlocale($category, $CURRENTLOCALE);
} else {
- $ret = 0;
- if (function_exists('setlocale')) // I don't know if this ever happens ;)
- $ret = @setlocale($category, $locale); //the @ hides warning messages on few installations
- if (($ret and $locale == '') or ($ret == $locale)) {
- $EMULATEGETTEXT = 0;
+ if (function_exists('setlocale')) {
+ $ret = setlocale($category, $locale);
+ if (($locale == '' and !$ret) or // failed setting it by env
+ ($locale != '' and $ret != $locale)) { // failed setting it
+ // Failed setting it according to environment.
+ $CURRENTLOCALE = _get_default_locale($locale);
+ $EMULATEGETTEXT = 1;
+ } else {
$CURRENTLOCALE = $ret;
+ $EMULATEGETTEXT = 0;
+ }
} else {
- if ($locale == '') // emulate variable support
- $CURRENTLOCALE = getenv('LANG');
- else
- $CURRENTLOCALE = $locale;
- $EMULATEGETTEXT = 1;
+ // No function setlocale(), emulate it all.
+ $CURRENTLOCALE = _get_default_locale($locale);
+ $EMULATEGETTEXT = 1;
}
+ // Allow locale to be changed on the go for one translation domain.
+ global $text_domains, $default_domain;
+ unset($text_domains[$default_domain]->l10n);
return $CURRENTLOCALE;
}
}
@@ -147,135 +238,240 @@ function _setlocale($category, $locale) {
* Sets the path for a domain.
*/
function _bindtextdomain($domain, $path) {
- global $text_domains;
- // ensure $path ends with a slash
- if ($path[strlen($path) - 1] != '/') $path .= '/';
- elseif ($path[strlen($path) - 1] != '\\') $path .= '\\';
- $text_domains[$domain]->path = $path;
+ global $text_domains;
+ // ensure $path ends with a slash ('/' should work for both, but lets still play nice)
+ if (substr(php_uname(), 0, 7) == "Windows") {
+ if ($path[strlen($path)-1] != '\\' and $path[strlen($path)-1] != '/')
+ $path .= '\\';
+ } else {
+ if ($path[strlen($path)-1] != '/')
+ $path .= '/';
+ }
+ if (!array_key_exists($domain, $text_domains)) {
+ // Initialize an empty domain object.
+ $text_domains[$domain] = new domain();
+ }
+ $text_domains[$domain]->path = $path;
}
/**
* Specify the character encoding in which the messages from the DOMAIN message catalog will be returned.
*/
function _bind_textdomain_codeset($domain, $codeset) {
- global $text_domains;
- $text_domains[$domain]->codeset = $codeset;
+ global $text_domains;
+ $text_domains[$domain]->codeset = $codeset;
}
/**
* Sets the default domain.
*/
function _textdomain($domain) {
- global $default_domain;
- $default_domain = $domain;
+ global $default_domain;
+ $default_domain = $domain;
}
/**
* Lookup a message in the current domain.
*/
function _gettext($msgid) {
- $l10n = _get_reader();
- //return $l10n->translate($msgid);
- return _encode($l10n->translate($msgid));
+ $l10n = _get_reader();
+ return _encode($l10n->translate($msgid));
}
+
/**
* Alias for gettext.
*/
function __($msgid) {
- return _gettext($msgid);
+ return _gettext($msgid);
}
+
/**
* Plural version of gettext.
*/
function _ngettext($single, $plural, $number) {
- $l10n = _get_reader();
- //return $l10n->ngettext($single, $plural, $number);
- return _encode($l10n->ngettext($single, $plural, $number));
+ $l10n = _get_reader();
+ return _encode($l10n->ngettext($single, $plural, $number));
}
/**
* Override the current domain.
*/
function _dgettext($domain, $msgid) {
- $l10n = _get_reader($domain);
- //return $l10n->translate($msgid);
- return _encode($l10n->translate($msgid));
+ $l10n = _get_reader($domain);
+ return _encode($l10n->translate($msgid));
}
+
/**
* Plural version of dgettext.
*/
function _dngettext($domain, $single, $plural, $number) {
- $l10n = _get_reader($domain);
- //return $l10n->ngettext($single, $plural, $number);
- return _encode($l10n->ngettext($single, $plural, $number));
+ $l10n = _get_reader($domain);
+ return _encode($l10n->ngettext($single, $plural, $number));
}
/**
* Overrides the domain and category for a single lookup.
*/
function _dcgettext($domain, $msgid, $category) {
- $l10n = _get_reader($domain, $category);
- //return $l10n->translate($msgid);
- return _encode($l10n->translate($msgid));
+ $l10n = _get_reader($domain, $category);
+ return _encode($l10n->translate($msgid));
}
/**
* Plural version of dcgettext.
*/
function _dcngettext($domain, $single, $plural, $number, $category) {
- $l10n = _get_reader($domain, $category);
- //return $l10n->ngettext($single, $plural, $number);
- return _encode($l10n->ngettext($single, $plural, $number));
+ $l10n = _get_reader($domain, $category);
+ return _encode($l10n->ngettext($single, $plural, $number));
+}
+
+/**
+ * Context version of gettext.
+ */
+function _pgettext($context, $msgid) {
+ $l10n = _get_reader();
+ return _encode($l10n->pgettext($context, $msgid));
+}
+
+/**
+ * Override the current domain in a context gettext call.
+ */
+function _dpgettext($domain, $context, $msgid) {
+ $l10n = _get_reader($domain);
+ return _encode($l10n->pgettext($context, $msgid));
+}
+
+/**
+ * Overrides the domain and category for a single context-based lookup.
+ */
+function _dcpgettext($domain, $context, $msgid, $category) {
+ $l10n = _get_reader($domain, $category);
+ return _encode($l10n->pgettext($context, $msgid));
+}
+
+/**
+ * Context version of ngettext.
+ */
+function _npgettext($context, $singular, $plural) {
+ $l10n = _get_reader();
+ return _encode($l10n->npgettext($context, $singular, $plural));
+}
+
+/**
+ * Override the current domain in a context ngettext call.
+ */
+function _dnpgettext($domain, $context, $singular, $plural) {
+ $l10n = _get_reader($domain);
+ return _encode($l10n->npgettext($context, $singular, $plural));
}
+/**
+ * Overrides the domain and category for a plural context-based lookup.
+ */
+function _dcnpgettext($domain, $context, $singular, $plural, $category) {
+ $l10n = _get_reader($domain, $category);
+ return _encode($l10n->npgettext($context, $singular, $plural));
+}
-// Wrappers to use if the standard gettext functions are available, but the current locale is not supported by the system.
-// Use the standard impl if the current locale is supported, use the custom impl otherwise.
+
+// Wrappers to use if the standard gettext functions are available,
+// but the current locale is not supported by the system.
+// Use the standard impl if the current locale is supported, use the
+// custom impl otherwise.
function T_setlocale($category, $locale) {
return _setlocale($category, $locale);
}
function T_bindtextdomain($domain, $path) {
- if (_check_locale()) return bindtextdomain($domain, $path);
- else return _bindtextdomain($domain, $path);
+ if (_check_locale_and_function()) return bindtextdomain($domain, $path);
+ else return _bindtextdomain($domain, $path);
}
function T_bind_textdomain_codeset($domain, $codeset) {
// bind_textdomain_codeset is available only in PHP 4.2.0+
- if (_check_locale() and function_exists('bind_textdomain_codeset')) return bind_textdomain_codeset($domain, $codeset);
- else return _bind_textdomain_codeset($domain, $codeset);
+ if (_check_locale_and_function('bind_textdomain_codeset'))
+ return bind_textdomain_codeset($domain, $codeset);
+ else return _bind_textdomain_codeset($domain, $codeset);
}
function T_textdomain($domain) {
- if (_check_locale()) return textdomain($domain);
- else return _textdomain($domain);
+ if (_check_locale_and_function()) return textdomain($domain);
+ else return _textdomain($domain);
}
function T_gettext($msgid) {
- if (_check_locale()) return gettext($msgid);
- else return _gettext($msgid);
+ if (_check_locale_and_function()) return gettext($msgid);
+ else return _gettext($msgid);
}
function T_($msgid) {
- if (_check_locale()) return _($msgid);
- return __($msgid);
+ if (_check_locale_and_function()) return _($msgid);
+ return __($msgid);
}
function T_ngettext($single, $plural, $number) {
- if (_check_locale()) return ngettext($single, $plural, $number);
- else return _ngettext($single, $plural, $number);
+ if (_check_locale_and_function())
+ return ngettext($single, $plural, $number);
+ else return _ngettext($single, $plural, $number);
}
function T_dgettext($domain, $msgid) {
- if (_check_locale()) return dgettext($domain, $msgid);
- else return _dgettext($domain, $msgid);
+ if (_check_locale_and_function()) return dgettext($domain, $msgid);
+ else return _dgettext($domain, $msgid);
}
function T_dngettext($domain, $single, $plural, $number) {
- if (_check_locale()) return dngettext($domain, $single, $plural, $number);
- else return _dngettext($domain, $single, $plural, $number);
+ if (_check_locale_and_function())
+ return dngettext($domain, $single, $plural, $number);
+ else return _dngettext($domain, $single, $plural, $number);
}
function T_dcgettext($domain, $msgid, $category) {
- if (_check_locale()) return dcgettext($domain, $msgid, $category);
- else return _dcgettext($domain, $msgid, $category);
+ if (_check_locale_and_function())
+ return dcgettext($domain, $msgid, $category);
+ else return _dcgettext($domain, $msgid, $category);
}
function T_dcngettext($domain, $single, $plural, $number, $category) {
- if (_check_locale()) return dcngettext($domain, $single, $plural, $number, $category);
- else return _dcngettext($domain, $single, $plural, $number, $category);
+ if (_check_locale_and_function())
+ return dcngettext($domain, $single, $plural, $number, $category);
+ else return _dcngettext($domain, $single, $plural, $number, $category);
+}
+
+function T_pgettext($context, $msgid) {
+ if (_check_locale_and_function('pgettext'))
+ return pgettext($context, $msgid);
+ else
+ return _pgettext($context, $msgid);
+}
+
+function T_dpgettext($domain, $context, $msgid) {
+ if (_check_locale_and_function('dpgettext'))
+ return dpgettext($domain, $context, $msgid);
+ else
+ return _dpgettext($domain, $context, $msgid);
+}
+
+function T_dcpgettext($domain, $context, $msgid, $category) {
+ if (_check_locale_and_function('dcpgettext'))
+ return dcpgettext($domain, $context, $msgid, $category);
+ else
+ return _dcpgettext($domain, $context, $msgid, $category);
+}
+
+function T_npgettext($context, $singular, $plural) {
+ if (_check_locale_and_function('npgettext'))
+ return npgettext($context, $single, $plural, $number);
+ else
+ return _npgettext($context, $single, $plural, $number);
+}
+
+function T_dnpgettext($domain, $context, $singular, $plural) {
+ if (_check_locale_and_function('dnpgettext'))
+ return dnpgettext($domain, $context, $single, $plural, $number);
+ else
+ return _dnpgettext($domain, $context, $single, $plural, $number);
+}
+
+function T_dcnpgettext($domain, $context, $singular, $plural, $category) {
+ if (_check_locale_and_function('dcnpgettext'))
+ return dcnpgettext($domain, $context, $single,
+ $plural, $number, $category);
+ else
+ return _dcnpgettext($domain, $context, $single,
+ $plural, $number, $category);
}
@@ -283,36 +479,56 @@ function T_dcngettext($domain, $single, $plural, $number, $category) {
// Wrappers used as a drop in replacement for the standard gettext functions
if (!function_exists('gettext')) {
- function bindtextdomain($domain, $path) {
- return _bindtextdomain($domain, $path);
- }
- function bind_textdomain_codeset($domain, $codeset) {
- return _bind_textdomain_codeset($domain, $codeset);
- }
- function textdomain($domain) {
- return _textdomain($domain);
- }
- function gettext($msgid) {
- return _gettext($msgid);
- }
- function _($msgid) {
- return __($msgid);
- }
- function ngettext($single, $plural, $number) {
- return _ngettext($single, $plural, $number);
- }
- function dgettext($domain, $msgid) {
- return _dgettext($domain, $msgid);
- }
- function dngettext($domain, $single, $plural, $number) {
- return _dngettext($domain, $single, $plural, $number);
- }
- function dcgettext($domain, $msgid, $category) {
- return _dcgettext($domain, $msgid, $category);
- }
- function dcngettext($domain, $single, $plural, $number, $category) {
- return _dcngettext($domain, $single, $plural, $number, $category);
- }
+ function bindtextdomain($domain, $path) {
+ return _bindtextdomain($domain, $path);
+ }
+ function bind_textdomain_codeset($domain, $codeset) {
+ return _bind_textdomain_codeset($domain, $codeset);
+ }
+ function textdomain($domain) {
+ return _textdomain($domain);
+ }
+ function gettext($msgid) {
+ return _gettext($msgid);
+ }
+ function _($msgid) {
+ return __($msgid);
+ }
+ function ngettext($single, $plural, $number) {
+ return _ngettext($single, $plural, $number);
+ }
+ function dgettext($domain, $msgid) {
+ return _dgettext($domain, $msgid);
+ }
+ function dngettext($domain, $single, $plural, $number) {
+ return _dngettext($domain, $single, $plural, $number);
+ }
+ function dcgettext($domain, $msgid, $category) {
+ return _dcgettext($domain, $msgid, $category);
+ }
+ function dcngettext($domain, $single, $plural, $number, $category) {
+ return _dcngettext($domain, $single, $plural, $number, $category);
+ }
+ function pgettext($context, $msgid) {
+ return _pgettext($context, $msgid);
+ }
+ function npgettext($context, $single, $plural, $number) {
+ return _npgettext($context, $single, $plural, $number);
+ }
+ function dpgettext($domain, $context, $msgid) {
+ return _dpgettext($domain, $context, $msgid);
+ }
+ function dnpgettext($domain, $context, $single, $plural, $number) {
+ return _dnpgettext($domain, $context, $single, $plural, $number);
+ }
+ function dcpgettext($domain, $context, $msgid, $category) {
+ return _dcpgettext($domain, $context, $msgid, $category);
+ }
+ function dcnpgettext($domain, $context, $single, $plural,
+ $number, $category) {
+ return _dcnpgettext($domain, $context, $single, $plural,
+ $number, $category);
+ }
}
?>
diff --git a/src/php-gettext/gettext.php b/src/php-gettext/gettext.php
index 978794c..a121f9c 100644
--- a/src/php-gettext/gettext.php
+++ b/src/php-gettext/gettext.php
@@ -1,8 +1,8 @@
<?php
/*
- Copyright (c) 2003 Danilo Segan <danilo@kvota.net>.
+ Copyright (c) 2003, 2009 Danilo Segan <danilo@kvota.net>.
Copyright (c) 2005 Nico Kaiser <nico@siriux.net>
-
+
This file is part of PHP-gettext.
PHP-gettext is free software; you can redistribute it and/or modify
@@ -20,13 +20,13 @@
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-
+
/**
* Provides a simple gettext replacement that works independently from
* the system's gettext abilities.
* It can read MO files and use them for translating strings.
* The files are passed to gettext_reader as a Stream (see streams.php)
- *
+ *
* This version has the ability to cache all strings and translations to
* speed up the string lookup.
* While the cache is enabled by default, it can be switched off with the
@@ -36,7 +36,7 @@
class gettext_reader {
//public:
var $error = 0; // public variable that holds error code (0 if no error)
-
+
//private:
var $BYTEORDER = 0; // 0: low endian, 1: big endian
var $STREAM = NULL;
@@ -52,27 +52,33 @@ class gettext_reader {
/* Methods */
-
-
+
+
/**
* Reads a 32bit Integer from the Stream
- *
+ *
* @access private
* @return Integer from the Stream
*/
function readint() {
if ($this->BYTEORDER == 0) {
// low endian
- return array_shift(unpack('V', $this->STREAM->read(4)));
+ $input=unpack('V', $this->STREAM->read(4));
+ return array_shift($input);
} else {
// big endian
- return array_shift(unpack('N', $this->STREAM->read(4)));
+ $input=unpack('N', $this->STREAM->read(4));
+ return array_shift($input);
}
}
+ function read($bytes) {
+ return $this->STREAM->read($bytes);
+ }
+
/**
* Reads an array of Integers from the Stream
- *
+ *
* @param int count How many elements should be read
* @return Array of Integers
*/
@@ -85,10 +91,10 @@ class gettext_reader {
return unpack('N'.$count, $this->STREAM->read(4 * $count));
}
}
-
+
/**
* Constructor
- *
+ *
* @param object Reader the StreamReader object
* @param boolean enable_cache Enable or disable caching of strings (default on)
*/
@@ -98,39 +104,37 @@ class gettext_reader {
$this->short_circuit = true;
return;
}
-
+
// Caching can be turned off
$this->enable_cache = $enable_cache;
- // $MAGIC1 = (int)0x950412de; //bug in PHP 5
- $MAGIC1 = (int) - 1794895138;
- // $MAGIC2 = (int)0xde120495; //bug
- $MAGIC2 = (int) - 569244523;
+ $MAGIC1 = "\x95\x04\x12\xde";
+ $MAGIC2 = "\xde\x12\x04\x95";
$this->STREAM = $Reader;
- $magic = $this->readint();
- if ($magic == $MAGIC1 || $magic == ($MAGIC1 & 0xFFFFFFFF)) {
- $this->BYTEORDER = 0;
- } elseif ($magic == $MAGIC2 || $magic == ($MAGIC2 & 0xFFFFFFFF)) {
+ $magic = $this->read(4);
+ if ($magic == $MAGIC1) {
$this->BYTEORDER = 1;
+ } elseif ($magic == $MAGIC2) {
+ $this->BYTEORDER = 0;
} else {
$this->error = 1; // not MO file
return false;
}
-
+
// FIXME: Do we care about revision? We should.
$revision = $this->readint();
-
+
$this->total = $this->readint();
$this->originals = $this->readint();
$this->translations = $this->readint();
}
-
+
/**
* Loads the translation tables from the MO file into the cache
* If caching is enabled, also loads all strings into a cache
* to speed up translation lookups
- *
+ *
* @access private
*/
function load_tables() {
@@ -138,13 +142,17 @@ class gettext_reader {
is_array($this->table_originals) &&
is_array($this->table_translations))
return;
-
+
/* get original and translations tables */
- $this->STREAM->seekto($this->originals);
- $this->table_originals = $this->readintarray($this->total * 2);
- $this->STREAM->seekto($this->translations);
- $this->table_translations = $this->readintarray($this->total * 2);
-
+ if (!is_array($this->table_originals)) {
+ $this->STREAM->seekto($this->originals);
+ $this->table_originals = $this->readintarray($this->total * 2);
+ }
+ if (!is_array($this->table_translations)) {
+ $this->STREAM->seekto($this->translations);
+ $this->table_translations = $this->readintarray($this->total * 2);
+ }
+
if ($this->enable_cache) {
$this->cache_translations = array ();
/* read all strings in the cache */
@@ -157,10 +165,10 @@ class gettext_reader {
}
}
}
-
+
/**
* Returns a string from the "originals" table
- *
+ *
* @access private
* @param int num Offset number of original string
* @return string Requested string if found, otherwise ''
@@ -174,10 +182,10 @@ class gettext_reader {
$data = $this->STREAM->read($length);
return (string)$data;
}
-
+
/**
* Returns a string from the "translations" table
- *
+ *
* @access private
* @param int num Offset number of original string
* @return string Requested string if found, otherwise ''
@@ -191,10 +199,10 @@ class gettext_reader {
$data = $this->STREAM->read($length);
return (string)$data;
}
-
+
/**
* Binary search for string
- *
+ *
* @access private
* @param string string
* @param int start (internally used in recursive function)
@@ -232,10 +240,10 @@ class gettext_reader {
return $this->find_string($string, $half, $end);
}
}
-
+
/**
* Translates a string
- *
+ *
* @access public
* @param string string to be translated
* @return string translated string (or original, if not found)
@@ -243,8 +251,8 @@ class gettext_reader {
function translate($string) {
if ($this->short_circuit)
return $string;
- $this->load_tables();
-
+ $this->load_tables();
+
if ($this->enable_cache) {
// Caching enabled, get translated string from cache
if (array_key_exists($string, $this->cache_translations))
@@ -262,16 +270,65 @@ class gettext_reader {
}
/**
+ * Sanitize plural form expression for use in PHP eval call.
+ *
+ * @access private
+ * @return string sanitized plural form expression
+ */
+ function sanitize_plural_expression($expr) {
+ // Get rid of disallowed characters.
+ $expr = preg_replace('@[^a-zA-Z0-9_:;\(\)\?\|\&=!<>+*/\%-]@', '', $expr);
+
+ // Add parenthesis for tertiary '?' operator.
+ $expr .= ';';
+ $res = '';
+ $p = 0;
+ for ($i = 0; $i < strlen($expr); $i++) {
+ $ch = $expr[$i];
+ switch ($ch) {
+ case '?':
+ $res .= ' ? (';
+ $p++;
+ break;
+ case ':':
+ $res .= ') : (';
+ break;
+ case ';':
+ $res .= str_repeat( ')', $p) . ';';
+ $p = 0;
+ break;
+ default:
+ $res .= $ch;
+ }
+ }
+ return $res;
+ }
+
+ /**
+ * Parse full PO header and extract only plural forms line.
+ *
+ * @access private
+ * @return string verbatim plural form header field
+ */
+ function extract_plural_forms_header_from_po_header($header) {
+ if (preg_match("/(^|\n)plural-forms: ([^\n]*)\n/i", $header, $regs))
+ $expr = $regs[2];
+ else
+ $expr = "nplurals=2; plural=n == 1 ? 0 : 1;";
+ return $expr;
+ }
+
+ /**
* Get possible plural forms from MO header
- *
+ *
* @access private
* @return string plural form header
*/
function get_plural_forms() {
- // lets assume message number 0 is header
+ // lets assume message number 0 is header
// this is true, right?
$this->load_tables();
-
+
// cache header field for plural forms
if (! is_string($this->pluralheader)) {
if ($this->enable_cache) {
@@ -279,18 +336,15 @@ class gettext_reader {
} else {
$header = $this->get_translation_string(0);
}
- if (eregi("plural-forms: ([^\n]*)\n", $header, $regs))
- $expr = $regs[1];
- else
- $expr = "nplurals=2; plural=n == 1 ? 0 : 1;";
- $this->pluralheader = $expr;
+ $expr = $this->extract_plural_forms_header_from_po_header($header);
+ $this->pluralheader = $this->sanitize_plural_expression($expr);
}
return $this->pluralheader;
}
/**
* Detects which plural form to take
- *
+ *
* @access private
* @param n count
* @return int array index of the right plural form
@@ -300,7 +354,7 @@ class gettext_reader {
$string = str_replace('nplurals',"\$total",$string);
$string = str_replace("n",$n,$string);
$string = str_replace('plural',"\$plural",$string);
-
+
$total = 0;
$plural = 0;
@@ -311,7 +365,7 @@ class gettext_reader {
/**
* Plural version of gettext
- *
+ *
* @access public
* @param string single
* @param string plural
@@ -327,12 +381,12 @@ class gettext_reader {
}
// find out the appropriate form
- $select = $this->select_string($number);
-
+ $select = $this->select_string($number);
+
// this should contains all strings separated by NULLs
- $key = $single.chr(0).$plural;
-
-
+ $key = $single . chr(0) . $plural;
+
+
if ($this->enable_cache) {
if (! array_key_exists($key, $this->cache_translations)) {
return ($number != 1) ? $plural : $single;
@@ -353,6 +407,15 @@ class gettext_reader {
}
}
+ function pgettext($context, $msgid) {
+ $key = $context . chr(4) . $msgid;
+ return $this->translate($key);
+ }
+
+ function npgettext($context, $singular, $plural, $number) {
+ $singular = $context . chr(4) . $singular;
+ return $this->ngettext($singular, $plural, $number);
+ }
}
?>
diff --git a/src/php-gettext/streams.php b/src/php-gettext/streams.php
index 4237de1..3cdc158 100644
--- a/src/php-gettext/streams.php
+++ b/src/php-gettext/streams.php
@@ -1,6 +1,6 @@
<?php
/*
- Copyright (c) 2003, 2005 Danilo Segan <danilo@kvota.net>.
+ Copyright (c) 2003, 2005, 2006, 2009 Danilo Segan <danilo@kvota.net>.
This file is part of PHP-gettext.
@@ -21,29 +21,29 @@
*/
-// Simple class to wrap file streams, string streams, etc.
-// seek is essential, and it should be byte stream
+ // Simple class to wrap file streams, string streams, etc.
+ // seek is essential, and it should be byte stream
class StreamReader {
// should return a string [FIXME: perhaps return array of bytes?]
function read($bytes) {
return false;
}
-
+
// should return new position
function seekto($position) {
return false;
}
-
+
// returns current position
function currentpos() {
return false;
}
-
+
// returns length of entire stream (limit for seekto()s)
function length() {
return false;
}
-}
+};
class StringReader {
var $_pos;
@@ -78,7 +78,7 @@ class StringReader {
return strlen($this->_str);
}
-}
+};
class FileReader {
@@ -93,8 +93,8 @@ class FileReader {
$this->_pos = 0;
$this->_fd = fopen($filename,'rb');
if (!$this->_fd) {
- $this->error = 3; // Cannot read file, probably permissions
- return false;
+ $this->error = 3; // Cannot read file, probably permissions
+ return false;
}
} else {
$this->error = 2; // File doesn't exist
@@ -115,7 +115,7 @@ class FileReader {
$bytes -= strlen($chunk);
}
$this->_pos = ftell($this->_fd);
-
+
return $data;
} else return '';
}
@@ -138,9 +138,9 @@ class FileReader {
fclose($this->_fd);
}
-}
+};
-// Preloads entire file in memory first, then creates a StringReader
+// Preloads entire file in memory first, then creates a StringReader
// over it (it assumes knowledge of StringReader internals)
class CachedFileReader extends StringReader {
function CachedFileReader($filename) {
@@ -150,8 +150,8 @@ class CachedFileReader extends StringReader {
$fd = fopen($filename,'rb');
if (!$fd) {
- $this->error = 3; // Cannot read file, probably permissions
- return false;
+ $this->error = 3; // Cannot read file, probably permissions
+ return false;
}
$this->_str = fread($fd, $length);
fclose($fd);
@@ -161,7 +161,7 @@ class CachedFileReader extends StringReader {
return false;
}
}
-}
+};
?>
diff --git a/src/php-gettext/tests/LocalesTest.php b/src/php-gettext/tests/LocalesTest.php
new file mode 100644
index 0000000..3000286
--- /dev/null
+++ b/src/php-gettext/tests/LocalesTest.php
@@ -0,0 +1,66 @@
+<?php
+require_once('PHPUnit/Framework.php');
+require_once('gettext.inc');
+
+class LocaleTest extends PHPUnit_Framework_TestCase
+{
+ public function test_setlocale()
+ {
+ // _setlocale defaults to a locale name from environment variable LANG.
+ putenv("LANG=sr_RS");
+ $this->assertEquals('sr_RS', _setlocale(LC_MESSAGES, 0));
+
+ // For an existing locale, it never needs emulation.
+ putenv("LANG=C");
+ _setlocale(LC_MESSAGES, "");
+ $this->assertEquals(0, locale_emulation());
+
+ // If we set it to a non-existent locale, it still works, but uses
+ // emulation.
+ _setlocale(LC_MESSAGES, "xxx_XXX");
+ $this->assertEquals('xxx_XXX', _setlocale(LC_MESSAGES, 0));
+ $this->assertEquals(1, locale_emulation());
+ }
+
+ public function test_get_list_of_locales()
+ {
+ // For a locale containing country code, we prefer
+ // full locale name, but if that's not found, fall back
+ // to the language only locale name.
+ $this->assertEquals(array("sr_RS", "sr"),
+ get_list_of_locales("sr_RS"));
+
+ // If language code is used, it's the only thing returned.
+ $this->assertEquals(array("sr"),
+ get_list_of_locales("sr"));
+
+ // There is support for language and charset only.
+ $this->assertEquals(array("sr.UTF-8", "sr"),
+ get_list_of_locales("sr.UTF-8"));
+
+ // It can also split out character set from the full locale name.
+ $this->assertEquals(array("sr_RS.UTF-8", "sr_RS", "sr"),
+ get_list_of_locales("sr_RS.UTF-8"));
+
+ // There is support for @modifier in locale names as well.
+ $this->assertEquals(array("sr_RS.UTF-8@latin", "sr_RS@latin", "sr@latin",
+ "sr_RS.UTF-8", "sr_RS", "sr"),
+ get_list_of_locales("sr_RS.UTF-8@latin"));
+
+ // We can pass in only language and modifier.
+ $this->assertEquals(array("sr@latin", "sr"),
+ get_list_of_locales("sr@latin"));
+
+
+ // If locale name is not following the regular POSIX pattern,
+ // it's used verbatim.
+ $this->assertEquals(array("something"),
+ get_list_of_locales("something"));
+
+ // Passing in an empty string returns an empty array.
+ $this->assertEquals(array(),
+ get_list_of_locales(""));
+ }
+}
+
+?>
diff --git a/src/php-gettext/tests/ParsingTest.php b/src/php-gettext/tests/ParsingTest.php
new file mode 100644
index 0000000..9b350b2
--- /dev/null
+++ b/src/php-gettext/tests/ParsingTest.php
@@ -0,0 +1,43 @@
+<?php
+require_once('PHPUnit/Framework.php');
+//require_once('gettext.php');
+
+class ParsingTest extends PHPUnit_Framework_TestCase
+{
+ public function test_extract_plural_forms_header_from_po_header()
+ {
+ $parser = new gettext_reader(NULL);
+ // It defaults to a "Western-style" plural header.
+ $this->assertEquals(
+ 'nplurals=2; plural=n == 1 ? 0 : 1;',
+ $parser->extract_plural_forms_header_from_po_header(""));
+
+ // Extracting it from the middle of the header works.
+ $this->assertEquals(
+ 'nplurals=1; plural=0;',
+ $parser->extract_plural_forms_header_from_po_header(
+ "Content-type: text/html; charset=UTF-8\n"
+ ."Plural-Forms: nplurals=1; plural=0;\n"
+ ."Last-Translator: nobody\n"
+ ));
+
+ // It's also case-insensitive.
+ $this->assertEquals(
+ 'nplurals=1; plural=0;',
+ $parser->extract_plural_forms_header_from_po_header(
+ "PLURAL-forms: nplurals=1; plural=0;\n"
+ ));
+
+ // It falls back to default if it's not on a separate line.
+ $this->assertEquals(
+ 'nplurals=2; plural=n == 1 ? 0 : 1;',
+ $parser->extract_plural_forms_header_from_po_header(
+ "Content-type: text/html; charset=UTF-8" // note the missing \n here
+ ."Plural-Forms: nplurals=1; plural=0;\n"
+ ."Last-Translator: nobody\n"
+ ));
+
+ }
+
+}
+?>
diff --git a/tests/AllTests.php b/tests/AllTests.php
index d29de7f..4afcc6b 100644
--- a/tests/AllTests.php
+++ b/tests/AllTests.php
@@ -17,9 +17,6 @@ if (!defined('PHPUnit_MAIN_METHOD')) {
}
require_once 'prepare.php';
-require_once 'PHPUnit/Framework/TestSuite.php';
-
-PHPUnit_Util_Filter::addFileToFilter(__FILE__);
/**
* SemanticScuttle unit tests.
@@ -64,6 +61,10 @@ class AllTests extends PHPUnit_Framework_TestSuite
$suite->addTestFile($tdir . '/TagTest.php');
$suite->addTestFile($tdir . '/VoteTest.php');
$suite->addTestFile($tdir . '/UserTest.php');
+ $suite->addTestFile($tdir . '/Api/ExportCsvTest.php');
+ $suite->addTestFile($tdir . '/Api/PostsAddTest.php');
+ $suite->addTestFile($tdir . '/Api/PostsDeleteTest.php');
+ $suite->addTestFile($tdir . '/Api/PostsUpdateTest.php');
return $suite;
}
diff --git a/tests/Api/PostsAddTest.php b/tests/Api/PostsAddTest.php
new file mode 100644
index 0000000..1f21d04
--- /dev/null
+++ b/tests/Api/PostsAddTest.php
@@ -0,0 +1,435 @@
+<?php
+/**
+ * SemanticScuttle - your social bookmark manager.
+ *
+ * PHP version 5.
+ *
+ * @category Bookmarking
+ * @package SemanticScuttle
+ * @author Benjamin Huynh-Kim-Bang <mensonge@users.sourceforge.net>
+ * @author Christian Weiske <cweiske@cweiske.de>
+ * @author Eric Dane <ericdane@users.sourceforge.net>
+ * @license GPL http://www.gnu.org/licenses/gpl.html
+ * @link http://sourceforge.net/projects/semanticscuttle
+ */
+
+require_once dirname(__FILE__) . '/../prepare.php';
+require_once 'HTTP/Request2.php';
+
+if (!defined('PHPUnit_MAIN_METHOD')) {
+ define('PHPUnit_MAIN_METHOD', 'Api_PostsAddTest::main');
+}
+
+/**
+ * Unit tests for the SemanticScuttle post addition API.
+ *
+ * @category Bookmarking
+ * @package SemanticScuttle
+ * @author Benjamin Huynh-Kim-Bang <mensonge@users.sourceforge.net>
+ * @author Christian Weiske <cweiske@cweiske.de>
+ * @author Eric Dane <ericdane@users.sourceforge.net>
+ * @license GPL http://www.gnu.org/licenses/gpl.html
+ * @link http://sourceforge.net/projects/semanticscuttle
+ */
+class Api_PostsAddTest extends TestBaseApi
+{
+ protected $urlPart = 'api/posts/add';
+
+
+
+ /**
+ * Used to run this test class standalone
+ *
+ * @return void
+ */
+ public static function main()
+ {
+ require_once 'PHPUnit/TextUI/TestRunner.php';
+ PHPUnit_TextUI_TestRunner::run(
+ new PHPUnit_Framework_TestSuite(__CLASS__)
+ );
+ }
+
+
+
+ /**
+ * Test if authentication is required when sending no auth data
+ */
+ public function testAuthWithoutAuthData()
+ {
+ $req = $this->getRequest(null, false);
+ $res = $req->send();
+ $this->assertEquals(401, $res->getStatus());
+ }
+
+
+
+ /**
+ * Test if authentication is required when sending wrong user data
+ */
+ public function testAuthWrongCredentials()
+ {
+ $req = $this->getRequest(null, false);
+ $req->setAuth('user', 'password', HTTP_Request2::AUTH_BASIC);
+ $res = $req->send();
+ $this->assertEquals(401, $res->getStatus());
+ }
+
+
+
+ /**
+ * Test if adding a bookmark via POST works.
+ */
+ public function testAddBookmarkPost()
+ {
+ $this->bs->deleteAll();
+
+ $bmUrl = 'http://example.org/tag-1';
+ $bmTags = array('foo', 'bar', 'baz');
+ $bmDatetime = '2010-09-08T03:02:01Z';
+ $bmTitle = 'This is a foo title';
+ $bmDescription = <<<TXT
+This is the description of
+my bookmark with some
+newlines and <some>?&\$ÄÖ'"§special"'
+characters
+TXT;
+
+ list($req, $uId) = $this->getAuthRequest();
+ $req->setMethod(HTTP_Request2::METHOD_POST);
+ $req->addPostParameter('url', $bmUrl);
+ $req->addPostParameter('description', $bmTitle);
+ $req->addPostParameter('extended', $bmDescription);
+ $req->addPostParameter('tags', implode(' ', $bmTags));
+ $req->addPostParameter('dt', $bmDatetime);
+ $res = $req->send();
+
+ //all should be well
+ $this->assertEquals(200, $res->getStatus());
+ //verify MIME content type
+ $this->assertEquals(
+ 'text/xml; charset=utf-8',
+ $res->getHeader('content-type')
+ );
+
+ //verify xml
+ $this->assertTag(
+ array(
+ 'tag' => 'result',
+ 'attributes' => array('code' => 'done')
+ ),
+ $res->getBody(),
+ null, false
+ );
+
+ //user should have one bookmark now
+ $data = $this->bs->getBookmarks(0, null, $uId);
+ $this->assertEquals(1, $data['total']);
+ $bm = $data['bookmarks'][0];
+
+ $this->assertEquals($bmUrl, $bm['bAddress']);
+ $this->assertEquals($bmTitle, $bm['bTitle']);
+ $this->assertEquals($bmDescription, $bm['bDescription']);
+ $this->assertEquals($bmTags, $bm['tags']);
+ $this->assertEquals(
+ gmdate('Y-m-d H:i:s', strtotime($bmDatetime)),
+ $bm['bDatetime']
+ );
+ }
+
+
+
+ /**
+ * Test if adding a bookmark via GET works.
+ */
+ public function testAddBookmarkGet()
+ {
+ $this->bs->deleteAll();
+
+ $bmUrl = 'http://example.org/tag-1';
+ $bmTags = array('foo', 'bar', 'baz');
+ $bmDatetime = '2010-09-08T03:02:01Z';
+ $bmTitle = 'This is a foo title';
+ $bmDescription = <<<TXT
+This is the description of
+my bookmark with some
+newlines and <some>?&\$ÄÖ'"§special"'
+characters
+TXT;
+
+ list($req, $uId) = $this->getAuthRequest(
+ '?url=' . urlencode($bmUrl)
+ . '&description=' . urlencode($bmTitle)
+ . '&extended=' . urlencode($bmDescription)
+ . '&tags=' . urlencode(implode(' ', $bmTags))
+ . '&dt=' . urlencode($bmDatetime)
+ );
+ $res = $req->send();
+
+ //all should be well
+ $this->assertEquals(200, $res->getStatus());
+ //verify MIME content type
+ $this->assertEquals(
+ 'text/xml; charset=utf-8',
+ $res->getHeader('content-type')
+ );
+
+ //verify xml
+ $this->assertTag(
+ array(
+ 'tag' => 'result',
+ 'attributes' => array('code' => 'done')
+ ),
+ $res->getBody(),
+ null, false
+ );
+
+ //user should have one bookmark now
+ $data = $this->bs->getBookmarks(0, null, $uId);
+ $this->assertEquals(1, $data['total']);
+ $bm = $data['bookmarks'][0];
+
+ $this->assertEquals($bmUrl, $bm['bAddress']);
+ $this->assertEquals($bmTitle, $bm['bTitle']);
+ $this->assertEquals($bmDescription, $bm['bDescription']);
+ $this->assertEquals($bmTags, $bm['tags']);
+ $this->assertEquals(
+ gmdate('Y-m-d H:i:s', strtotime($bmDatetime)),
+ $bm['bDatetime']
+ );
+ }
+
+ /**
+ * Verify that the URL and description/title are enough parameters
+ * to add a bookmark.
+ */
+ public function testUrlDescEnough()
+ {
+ $this->bs->deleteAll();
+
+ list($req, $uId) = $this->getAuthRequest();
+ $req->setMethod(HTTP_Request2::METHOD_POST);
+ $req->addPostParameter('url', 'http://example.org/tag2');
+ $req->addPostParameter('description', 'foo bar');
+ $res = $req->send();
+
+ //all should be well
+ $this->assertEquals(200, $res->getStatus());
+ //verify MIME content type
+ $this->assertEquals(
+ 'text/xml; charset=utf-8',
+ $res->getHeader('content-type')
+ );
+
+ //verify xml
+ $this->assertTag(
+ array(
+ 'tag' => 'result',
+ 'attributes' => array('code' => 'done')
+ ),
+ $res->getBody(),
+ null, false
+ );
+
+ //user has 1 bookmark now
+ $data = $this->bs->getBookmarks(0, null, $uId);
+ $this->assertEquals(1, $data['total']);
+ }
+
+ /**
+ * Verify that the URL is required
+ */
+ public function testUrlRequired()
+ {
+ $this->bs->deleteAll();
+
+ list($req, $uId) = $this->getAuthRequest();
+ $req->setMethod(HTTP_Request2::METHOD_POST);
+ //$req->addPostParameter('url', 'http://example.org/tag2');
+ $req->addPostParameter('description', 'foo bar');
+ $res = $req->send();
+
+ //all should be well
+ $this->assertEquals(400, $res->getStatus());
+ //verify MIME content type
+ $this->assertEquals(
+ 'text/xml; charset=utf-8',
+ $res->getHeader('content-type')
+ );
+
+ //verify xml
+ $this->assertTag(
+ array(
+ 'tag' => 'result',
+ 'attributes' => array('code' => 'URL missing')
+ ),
+ $res->getBody(),
+ null, false
+ );
+
+ //user still has 0 bookmarks
+ $data = $this->bs->getBookmarks(0, null, $uId);
+ $this->assertEquals(0, $data['total']);
+ }
+
+ /**
+ * Verify that the description/title is required
+ */
+ public function testDescriptionRequired()
+ {
+ $this->bs->deleteAll();
+
+ list($req, $uId) = $this->getAuthRequest();
+ $req->setMethod(HTTP_Request2::METHOD_POST);
+ $req->addPostParameter('url', 'http://example.org/tag2');
+ $res = $req->send();
+
+ //all should be well
+ $this->assertEquals(400, $res->getStatus());
+ //verify MIME content type
+ $this->assertEquals(
+ 'text/xml; charset=utf-8',
+ $res->getHeader('content-type')
+ );
+
+ //verify xml
+ $this->assertTag(
+ array(
+ 'tag' => 'result',
+ 'attributes' => array('code' => 'Description missing')
+ ),
+ $res->getBody(),
+ null, false
+ );
+
+ //user still has 0 bookmarks
+ $data = $this->bs->getBookmarks(0, null, $uId);
+ $this->assertEquals(0, $data['total']);
+ }
+
+ /**
+ * Test that the replace=no parameter prevents the bookmark from being
+ * overwritten.
+ */
+ public function testReplaceNo()
+ {
+ $this->bs->deleteAll();
+
+ $url = 'http://example.org/tag2';
+ $title1 = 'foo bar 1';
+ $title2 = 'bar 2 foo';
+
+ list($req, $uId) = $this->getAuthRequest();
+ $req->setMethod(HTTP_Request2::METHOD_POST);
+ $req->addPostParameter('url', $url);
+ $req->addPostParameter('description', $title1);
+ $res = $req->send();
+
+ //all should be well
+ $this->assertEquals(200, $res->getStatus());
+
+ //send it a second time, with different title
+ list($req, $dummy) = $this->getAuthRequest();
+ $req->setMethod(HTTP_Request2::METHOD_POST);
+ $req->addPostParameter('url', $url);
+ $req->addPostParameter('description', $title2);
+ $req->addPostParameter('replace', 'no');
+ $res = $req->send();
+
+ //this time we should get an error
+ $this->assertEquals(409, $res->getStatus());
+ //verify MIME content type
+ $this->assertEquals(
+ 'text/xml; charset=utf-8',
+ $res->getHeader('content-type')
+ );
+
+ //verify xml
+ $this->assertTag(
+ array(
+ 'tag' => 'result',
+ 'attributes' => array('code' => 'bookmark does already exist')
+ ),
+ $res->getBody(),
+ null, false
+ );
+
+ //user still has 1 bookmark now
+ $data = $this->bs->getBookmarks(0, null, $uId);
+ $this->assertEquals(1, $data['total']);
+ $this->assertEquals($title1, $data['bookmarks'][0]['bTitle']);
+
+ //send it a third time, without the replace parameter
+ // it defaults to "no", so the bookmark should not get overwritten
+ list($req, $dummy) = $this->getAuthRequest();
+ $req->setMethod(HTTP_Request2::METHOD_POST);
+ $req->addPostParameter('url', $url);
+ $req->addPostParameter('description', $title2);
+ $res = $req->send();
+
+ //this time we should get an error
+ $this->assertEquals(409, $res->getStatus());
+
+ //bookmark should not have changed
+ $data = $this->bs->getBookmarks(0, null, $uId);
+ $this->assertEquals(1, $data['total']);
+ $this->assertEquals($title1, $data['bookmarks'][0]['bTitle']);
+ }
+
+ /**
+ * Test that the replace=yes parameter causes the bookmark to be updated.
+ */
+ public function testReplaceYes()
+ {
+ $this->bs->deleteAll();
+
+ $url = 'http://example.org/tag2';
+ $title1 = 'foo bar 1';
+ $title2 = 'bar 2 foo';
+
+ list($req, $uId) = $this->getAuthRequest();
+ $req->setMethod(HTTP_Request2::METHOD_POST);
+ $req->addPostParameter('url', $url);
+ $req->addPostParameter('description', $title1);
+ $res = $req->send();
+
+ //all should be well
+ $this->assertEquals(200, $res->getStatus());
+
+ //send it a second time, with different title
+ list($req, $dummy) = $this->getAuthRequest();
+ $req->setMethod(HTTP_Request2::METHOD_POST);
+ $req->addPostParameter('url', $url);
+ $req->addPostParameter('description', $title2);
+ $req->addPostParameter('replace', 'yes');
+ $res = $req->send();
+
+ //no error
+ $this->assertEquals(200, $res->getStatus());
+ //verify MIME content type
+ $this->assertEquals(
+ 'text/xml; charset=utf-8',
+ $res->getHeader('content-type')
+ );
+
+ //verify xml
+ $this->assertTag(
+ array(
+ 'tag' => 'result',
+ 'attributes' => array('code' => 'done')
+ ),
+ $res->getBody(),
+ null, false
+ );
+
+ //user still has 1 bookmark now, but with the new title
+ $data = $this->bs->getBookmarks(0, null, $uId);
+ $this->assertEquals(1, $data['total']);
+ $this->assertEquals($title2, $data['bookmarks'][0]['bTitle']);
+ }
+}
+
+if (PHPUnit_MAIN_METHOD == 'Api_PostsAddTest::main') {
+ Api_PostsAddTest::main();
+}
+?> \ No newline at end of file
diff --git a/tests/Api/PostsDeleteTest.php b/tests/Api/PostsDeleteTest.php
new file mode 100644
index 0000000..d9fb6cd
--- /dev/null
+++ b/tests/Api/PostsDeleteTest.php
@@ -0,0 +1,303 @@
+<?php
+/**
+ * SemanticScuttle - your social bookmark manager.
+ *
+ * PHP version 5.
+ *
+ * @category Bookmarking
+ * @package SemanticScuttle
+ * @author Benjamin Huynh-Kim-Bang <mensonge@users.sourceforge.net>
+ * @author Christian Weiske <cweiske@cweiske.de>
+ * @author Eric Dane <ericdane@users.sourceforge.net>
+ * @license GPL http://www.gnu.org/licenses/gpl.html
+ * @link http://sourceforge.net/projects/semanticscuttle
+ */
+
+require_once dirname(__FILE__) . '/../prepare.php';
+require_once 'HTTP/Request2.php';
+
+if (!defined('PHPUnit_MAIN_METHOD')) {
+ define('PHPUnit_MAIN_METHOD', 'Api_PostsDeleteTest::main');
+}
+
+/**
+ * Unit tests for the SemanticScuttle post deletion API.
+ *
+ * @category Bookmarking
+ * @package SemanticScuttle
+ * @author Benjamin Huynh-Kim-Bang <mensonge@users.sourceforge.net>
+ * @author Christian Weiske <cweiske@cweiske.de>
+ * @author Eric Dane <ericdane@users.sourceforge.net>
+ * @license GPL http://www.gnu.org/licenses/gpl.html
+ * @link http://sourceforge.net/projects/semanticscuttle
+ */
+class Api_PostsDeleteTest extends TestBaseApi
+{
+ protected $urlPart = 'api/posts/delete';
+
+
+
+ /**
+ * Used to run this test class standalone
+ *
+ * @return void
+ */
+ public static function main()
+ {
+ require_once 'PHPUnit/TextUI/TestRunner.php';
+ PHPUnit_TextUI_TestRunner::run(
+ new PHPUnit_Framework_TestSuite(__CLASS__)
+ );
+ }
+
+
+
+ /**
+ * Test if authentication is required when sending no auth data
+ */
+ public function testAuthWithoutAuthData()
+ {
+ $req = $this->getRequest(null, false);
+ $res = $req->send();
+ $this->assertEquals(401, $res->getStatus());
+ }
+
+
+
+ /**
+ * Test if authentication is required when sending wrong user data
+
+ */
+ public function testAuthWrongCredentials()
+ {
+ $req = $this->getRequest(null, false);
+ $req->setAuth('user', 'password', HTTP_Request2::AUTH_BASIC);
+ $res = $req->send();
+ $this->assertEquals(401, $res->getStatus());
+ }
+
+
+
+ /**
+ * Test if deleting an own bookmark works.
+ */
+ public function testDeleteOwnBookmark()
+ {
+ $this->bs->deleteAll();
+
+ $bookmarkUrl = 'http://example.org/tag-1';
+
+ list($req, $uId) = $this->getAuthRequest(
+ '?url=' . urlencode($bookmarkUrl)
+ );
+
+ $bId = $this->addBookmark(
+ $uId, $bookmarkUrl, 0,
+ array('unittest', 'tag1')
+ );
+ //user has one bookmark now
+ $data = $this->bs->getBookmarks(0, null, $uId);
+ $this->assertEquals(1, $data['total']);
+
+ //send request
+ $res = $req->send();
+
+ $this->assertEquals(200, $res->getStatus());
+ //verify MIME content type
+ $this->assertEquals(
+ 'text/xml; charset=utf-8',
+ $res->getHeader('content-type')
+ );
+
+ //verify xml
+ $this->assertTag(
+ array(
+ 'tag' => 'result',
+ 'attributes' => array('code' => 'done')
+ ),
+ $res->getBody(),
+ null, false
+ );
+
+ //bookmark should be deleted now
+ $data = $this->bs->getBookmarks(0, null, $uId);
+ $this->assertEquals(0, $data['total']);
+ }
+
+
+
+ /**
+ * Test if deleting an own bookmark via POST works.
+ */
+ public function testDeleteOwnBookmarkPost()
+ {
+ $this->bs->deleteAll();
+
+ $bookmarkUrl = 'http://example.org/tag-1';
+
+ list($req, $uId) = $this->getAuthRequest();
+
+ $bId = $this->addBookmark(
+ $uId, $bookmarkUrl, 0,
+ array('unittest', 'tag1')
+ );
+ //user has one bookmark now
+ $data = $this->bs->getBookmarks(0, null, $uId);
+ $this->assertEquals(1, $data['total']);
+
+ //send request
+ $req->setMethod(HTTP_Request2::METHOD_POST);
+ $req->addPostParameter('url', $bookmarkUrl);
+ $res = $req->send();
+
+ $this->assertEquals(200, $res->getStatus());
+ //verify MIME content type
+ $this->assertEquals(
+ 'text/xml; charset=utf-8',
+ $res->getHeader('content-type')
+ );
+
+ //verify xml
+ $this->assertTag(
+ array(
+ 'tag' => 'result',
+ 'attributes' => array('code' => 'done')
+ ),
+ $res->getBody(),
+ null, false
+ );
+
+ //bookmark should be deleted now
+ $data = $this->bs->getBookmarks(0, null, $uId);
+ $this->assertEquals(0, $data['total']);
+ }
+
+
+
+ /**
+ * Verify that deleting a bookmark of a different does not work
+ */
+ public function testDeleteOtherBookmark()
+ {
+ $this->bs->deleteAll();
+
+ $bookmarkUrl = 'http://example.org/tag-1';
+
+ list($req, $uId) = $this->getAuthRequest(
+ '?url=' . urlencode($bookmarkUrl)
+ );
+ $uId2 = $this->addUser();
+
+ $bId = $this->addBookmark(
+ $uId2, $bookmarkUrl, 0,
+ array('unittest', 'tag1')
+ );
+ //user 1 has no bookmarks
+ $data = $this->bs->getBookmarks(0, null, $uId);
+ $this->assertEquals(0, $data['total']);
+ //user 2 has one bookmark
+ $data = $this->bs->getBookmarks(0, null, $uId2);
+ $this->assertEquals(1, $data['total']);
+
+ //send request
+ $res = $req->send();
+
+ //404 - user does not have that bookmark
+ $this->assertEquals(404, $res->getStatus());
+
+ //verify MIME content type
+ $this->assertEquals(
+ 'text/xml; charset=utf-8',
+ $res->getHeader('content-type')
+ );
+
+ //verify xml
+ $this->assertTag(
+ array(
+ 'tag' => 'result',
+ 'attributes' => array('code' => 'item not found')
+ ),
+ $res->getBody(),
+ '', false
+ );
+
+ //bookmark should still be there
+ $data = $this->bs->getBookmarks(0, null, $uId2);
+ $this->assertEquals(1, $data['total']);
+ }
+
+
+
+ /**
+ * Test if deleting a bookmark works that also other users
+ * bookmarked.
+ */
+ public function testDeleteBookmarkOneOfTwo()
+ {
+ $this->bs->deleteAll();
+
+ $bookmarkUrl = 'http://example.org/tag-1';
+
+ list($req, $uId) = $this->getAuthRequest(
+ '?url=' . urlencode($bookmarkUrl)
+ );
+ $uId2 = $this->addUser();
+ $uId3 = $this->addUser();
+
+ //important: the order of addition is crucial here
+ $this->addBookmark(
+ $uId2, $bookmarkUrl, 0,
+ array('unittest', 'tag1')
+ );
+ $bId = $this->addBookmark(
+ $uId, $bookmarkUrl, 0,
+ array('unittest', 'tag1')
+ );
+ $this->addBookmark(
+ $uId3, $bookmarkUrl, 0,
+ array('unittest', 'tag1')
+ );
+
+ //user one and two have a bookmark now
+ $data = $this->bs->getBookmarks(0, null, $uId);
+ $this->assertEquals(1, $data['total']);
+ $data = $this->bs->getBookmarks(0, null, $uId2);
+ $this->assertEquals(1, $data['total']);
+
+ //send request
+ $res = $req->send();
+
+ $this->assertEquals(200, $res->getStatus());
+ //verify MIME content type
+ $this->assertEquals(
+ 'text/xml; charset=utf-8',
+ $res->getHeader('content-type')
+ );
+
+ //verify xml
+ $this->assertTag(
+ array(
+ 'tag' => 'result',
+ 'attributes' => array('code' => 'done')
+ ),
+ $res->getBody(),
+ '', false
+ );
+
+ //bookmark should be deleted now
+ $data = $this->bs->getBookmarks(0, null, $uId);
+ $this->assertEquals(0, $data['total']);
+ //user 2 should still have his
+ $data = $this->bs->getBookmarks(0, null, $uId2);
+ $this->assertEquals(1, $data['total']);
+ //user 3 should still have his, too
+ $data = $this->bs->getBookmarks(0, null, $uId3);
+ $this->assertEquals(1, $data['total']);
+ }
+
+}
+
+if (PHPUnit_MAIN_METHOD == 'Api_PostsDeleteTest::main') {
+ Api_PostsDeleteTest::main();
+}
+?> \ No newline at end of file
diff --git a/tests/Api/PostsUpdateTest.php b/tests/Api/PostsUpdateTest.php
new file mode 100644
index 0000000..c497a55
--- /dev/null
+++ b/tests/Api/PostsUpdateTest.php
@@ -0,0 +1,135 @@
+<?php
+/**
+ * SemanticScuttle - your social bookmark manager.
+ *
+ * PHP version 5.
+ *
+ * @category Bookmarking
+ * @package SemanticScuttle
+ * @author Benjamin Huynh-Kim-Bang <mensonge@users.sourceforge.net>
+ * @author Christian Weiske <cweiske@cweiske.de>
+ * @author Eric Dane <ericdane@users.sourceforge.net>
+ * @license GPL http://www.gnu.org/licenses/gpl.html
+ * @link http://sourceforge.net/projects/semanticscuttle
+ */
+
+require_once dirname(__FILE__) . '/../prepare.php';
+require_once 'HTTP/Request2.php';
+
+if (!defined('PHPUnit_MAIN_METHOD')) {
+ define('PHPUnit_MAIN_METHOD', 'Api_PostsUpdateTest::main');
+}
+
+/**
+ * Unit tests for the SemanticScuttle last-update time API.
+ *
+ * @category Bookmarking
+ * @package SemanticScuttle
+ * @author Benjamin Huynh-Kim-Bang <mensonge@users.sourceforge.net>
+ * @author Christian Weiske <cweiske@cweiske.de>
+ * @author Eric Dane <ericdane@users.sourceforge.net>
+ * @license GPL http://www.gnu.org/licenses/gpl.html
+ * @link http://sourceforge.net/projects/semanticscuttle
+ */
+class Api_PostsUpdateTest extends TestBaseApi
+{
+ protected $urlPart = 'api/posts/update';
+
+
+
+ /**
+ * Used to run this test class standalone
+ *
+ * @return void
+ */
+ public static function main()
+ {
+ require_once 'PHPUnit/TextUI/TestRunner.php';
+ PHPUnit_TextUI_TestRunner::run(
+ new PHPUnit_Framework_TestSuite(__CLASS__)
+ );
+ }
+
+
+
+ /**
+ * Test if authentication is required when sending no auth data
+ */
+ public function testAuthWithoutAuthData()
+ {
+ $req = $this->getRequest(null, false);
+ $res = $req->send();
+ $this->assertEquals(401, $res->getStatus());
+ }
+
+
+
+ /**
+ * Test if authentication is required when sending wrong user data
+
+ */
+ public function testAuthWrongCredentials()
+ {
+ $req = $this->getRequest(null, false);
+ $req->setAuth('user', 'password', HTTP_Request2::AUTH_BASIC);
+ $res = $req->send();
+ $this->assertEquals(401, $res->getStatus());
+ }
+
+
+
+ /**
+ * See if posts/update behaves correct if there is one bookmark
+ */
+ public function testPostUpdateOneBookmark()
+ {
+ $this->bs->deleteAll();
+
+ list($req, $uId) = $this->getAuthRequest();
+ $bId = $this->addBookmark(
+ $uId, 'http://example.org/tag1', 0,
+ array('unittest', 'tag1')
+ );
+
+ $data = $this->bs->getBookmarks(0, null, $uId);
+ $this->assertEquals(1, $data['total']);
+ $bookmark = $data['bookmarks'][0];
+
+ //send request
+ $res = $req->send();
+
+ $this->assertEquals(200, $res->getStatus());
+ //verify MIME content type
+ $this->assertEquals(
+ 'text/xml; charset=utf-8',
+ $res->getHeader('content-type')
+ );
+
+ //verify xml
+ $this->assertTag(
+ array(
+ 'tag' => 'update',
+ 'attributes' => array(
+ 'inboxnew' => '0'
+ )
+ ),
+ $res->getBody(),
+ '', false
+ );
+ //check time
+ $xml = simplexml_load_string($res->getBody());
+ $this->assertTrue(isset($xml['time']));
+ $this->assertEquals(
+ strtotime($bookmark['bDatetime']),
+ strtotime(
+ (string)$xml['time']
+ )
+ );
+ }
+
+}
+
+if (PHPUnit_MAIN_METHOD == 'Api_PostsUpdateTest::main') {
+ Api_PostsUpdateTest::main();
+}
+?> \ No newline at end of file
diff --git a/tests/Bookmark2TagTest.php b/tests/Bookmark2TagTest.php
index 14b71cc..fff4222 100644
--- a/tests/Bookmark2TagTest.php
+++ b/tests/Bookmark2TagTest.php
@@ -12,13 +12,12 @@
* @license GPL http://www.gnu.org/licenses/gpl.html
* @link http://sourceforge.net/projects/semanticscuttle
*/
-
-require_once 'prepare.php';
-
if (!defined('PHPUnit_MAIN_METHOD')) {
define('PHPUnit_MAIN_METHOD', 'Bookmark2TagTest::main');
}
+require_once 'prepare.php';
+
/**
* Unit tests for the SemanticScuttle bookmark-tag combination service.
*
@@ -38,6 +37,26 @@ class Bookmark2TagTest extends TestBase
protected $tts;
+ /**
+ * Create a bookmark. Like addBookmark(), just with other paramter order
+ * to make some tests in that class easier to write.
+ *
+ * @param integer $user User ID the bookmark shall belong
+ * @param array $tags Array of tags to attach. If "null" is given,
+ * it will automatically be "unittest"
+ * @param string $date strtotime-compatible string
+ * @param string $title Bookmark title
+ *
+ * @return integer ID of bookmark
+ */
+ protected function addTagBookmark($user, $tags, $date = null, $title = null)
+ {
+ return $this->addBookmark(
+ $user, null, 0, $tags, $title, $date
+ );
+ }
+
+
/**
* Used to run this test class standalone
@@ -57,6 +76,7 @@ class Bookmark2TagTest extends TestBase
protected function setUp()
{
$this->us = SemanticScuttle_Service_Factory::get('User');
+ $this->us->deleteAll();
$this->bs = SemanticScuttle_Service_Factory::get('Bookmark');
$this->bs->deleteAll();
$this->b2ts= SemanticScuttle_Service_Factory::get('Bookmark2Tag');
@@ -74,7 +94,7 @@ class Bookmark2TagTest extends TestBase
/**
* Test getTagsForBookmark() when the bookmark has no tags
*
- * @return void
+ * @covers SemanticScuttle_Service_Bookmark2Tag::getTagsForBookmark
*/
public function testGetTagsForBookmarkNone()
{
@@ -92,7 +112,7 @@ class Bookmark2TagTest extends TestBase
/**
* Test getTagsForBookmark() when the bookmark has one tag
*
- * @return void
+ * @covers SemanticScuttle_Service_Bookmark2Tag::getTagsForBookmark
*/
public function testGetTagsForBookmarkOne()
{
@@ -111,9 +131,9 @@ class Bookmark2TagTest extends TestBase
/**
* Test getTagsForBookmark() when the bookmark has three tags
*
- * @return void
+ * @covers SemanticScuttle_Service_Bookmark2Tag::getTagsForBookmark
*/
- public function testGetTagsForBookmarkThree()
+ public function testGetTagsForBookmarkThr()
{
$this->addBookmark(null, null, 0, array('forz', 'barz'));
@@ -121,7 +141,7 @@ class Bookmark2TagTest extends TestBase
$this->b2ts->attachTags($bid, array('foo', 'bar', 'fuu'));
$tags = $this->b2ts->getTagsForBookmark($bid);
- $this->assertType('array', $tags);
+ $this->assertInternalType('array', $tags);
$this->assertContains('foo', $tags);
$this->assertContains('bar', $tags);
$this->assertContains('fuu', $tags);
@@ -132,7 +152,7 @@ class Bookmark2TagTest extends TestBase
/**
* Test getTagsForBookmarks() when no bookmarks have tags.
*
- * @return void
+ * @covers SemanticScuttle_Service_Bookmark2Tag::getTagsForBookmarks
*/
public function testGetTagsForBookmarksNone()
{
@@ -142,10 +162,10 @@ class Bookmark2TagTest extends TestBase
$alltags = $this->b2ts->getTagsForBookmarks(
array($bid1, $bid2)
);
- $this->assertType('array', $alltags);
+ $this->assertInternalType('array', $alltags);
$this->assertEquals(2, count($alltags));
- $this->assertType('array', $alltags[$bid1]);
- $this->assertType('array', $alltags[$bid2]);
+ $this->assertInternalType('array', $alltags[$bid1]);
+ $this->assertInternalType('array', $alltags[$bid2]);
$this->assertEquals(0, count($alltags[$bid1]));
$this->assertEquals(0, count($alltags[$bid2]));
}
@@ -155,7 +175,7 @@ class Bookmark2TagTest extends TestBase
/**
* Test getTagsForBookmarks() when most bookmarks have tags.
*
- * @return void
+ * @covers SemanticScuttle_Service_Bookmark2Tag::getTagsForBookmarks
*/
public function testGetTagsForBookmarksMost()
{
@@ -180,9 +200,9 @@ class Bookmark2TagTest extends TestBase
$alltags = $this->b2ts->getTagsForBookmarks(
array($bid1, $bid2, $bid3, $bid4)
);
- $this->assertType('array', $alltags);
+ $this->assertInternalType('array', $alltags);
foreach ($alltags as $bid => $btags) {
- $this->assertType('array', $btags);
+ $this->assertInternalType('array', $btags);
if ($bid == $bid1) {
$this->assertEquals(3, count($btags));
$this->assertContains('foo', $btags);
@@ -205,6 +225,408 @@ class Bookmark2TagTest extends TestBase
}
}
}
+
+
+
+ /**
+ * Fetch the most popular tags in descending order
+ *
+ * @covers SemanticScuttle_Service_Bookmark2Tag::getPopularTags
+ */
+ public function testGetPopularTagsOrder()
+ {
+ $user = $this->addUser();
+ $this->addTagBookmark($user, array('one', 'two'));
+ $this->addTagBookmark($user, array('one', 'thr'));
+ $this->addTagBookmark($user, array('one', 'two'));
+
+ $arTags = $this->b2ts->getPopularTags();
+ $this->assertInternalType('array', $arTags);
+ $this->assertEquals(3, count($arTags));
+
+ $this->assertInternalType('array', $arTags[0]);
+
+ $this->assertEquals(
+ array(
+ array('tag' => 'one', 'bCount' => '3'),
+ array('tag' => 'two', 'bCount' => '2'),
+ array('tag' => 'thr', 'bCount' => '1')
+ ),
+ $arTags
+ );
+ }
+
+
+
+ /**
+ * @covers SemanticScuttle_Service_Bookmark2Tag::getPopularTags
+ */
+ public function testGetPopularTagsLimit()
+ {
+ $user = $this->addUser();
+ $this->addTagBookmark($user, array('one', 'two'));
+ $this->addTagBookmark($user, array('one', 'thr'));
+ $this->addTagBookmark($user, array('one', 'two'));
+
+ $arTags = $this->b2ts->getPopularTags();
+ $this->assertInternalType('array', $arTags);
+ $this->assertEquals(3, count($arTags));
+
+ $arTags = $this->b2ts->getPopularTags(null, 2);
+ $this->assertInternalType('array', $arTags);
+ $this->assertEquals(2, count($arTags));
+ $this->assertEquals(
+ array(
+ array('tag' => 'one', 'bCount' => '3'),
+ array('tag' => 'two', 'bCount' => '2'),
+ ),
+ $arTags
+ );
+
+ $arTags = $this->b2ts->getPopularTags(null, 1);
+ $this->assertInternalType('array', $arTags);
+ $this->assertEquals(1, count($arTags));
+ $this->assertEquals(
+ array(
+ array('tag' => 'one', 'bCount' => '3'),
+ ),
+ $arTags
+ );
+ }
+
+
+
+ /**
+ * @covers SemanticScuttle_Service_Bookmark2Tag::getPopularTags
+ */
+ public function testGetPopularTagsDays()
+ {
+ $user = $this->addUser();
+ $this->addTagBookmark($user, array('one', 'two'), 'today');
+ $this->addTagBookmark($user, array('one', 'thr'), 'today');
+ $this->addTagBookmark($user, array('one', 'two'), '-1 day 1 hour');
+ $this->addTagBookmark($user, array('one', 'thr'), '-3 days 1 hour');
+
+ $arTags = $this->b2ts->getPopularTags(null, 10, null, 1);
+ $this->assertInternalType('array', $arTags);
+ $this->assertEquals(3, count($arTags));
+ $this->assertContains(array('tag' => 'one', 'bCount' => '2'), $arTags);
+ $this->assertContains(array('tag' => 'two', 'bCount' => '1'), $arTags);
+ $this->assertContains(array('tag' => 'thr', 'bCount' => '1'), $arTags);
+
+ $arTags = $this->b2ts->getPopularTags(null, 10, null, 2);
+ $this->assertInternalType('array', $arTags);
+ $this->assertEquals(3, count($arTags));
+ $this->assertEquals(
+ array(
+ array('tag' => 'one', 'bCount' => '3'),
+ array('tag' => 'two', 'bCount' => '2'),
+ array('tag' => 'thr', 'bCount' => '1'),
+ ),
+ $arTags
+ );
+
+ $arTags = $this->b2ts->getPopularTags(null, 10, null, 5);
+ $this->assertInternalType('array', $arTags);
+ $this->assertEquals(3, count($arTags));
+ $this->assertContains(array('tag' => 'one', 'bCount' => '4'), $arTags);
+ $this->assertContains(array('tag' => 'two', 'bCount' => '2'), $arTags);
+ $this->assertContains(array('tag' => 'thr', 'bCount' => '2'), $arTags);
+ }
+
+ /**
+ * @covers SemanticScuttle_Service_Bookmark2Tag::getPopularTags
+ */
+ public function testGetPopularTagsBeginsWith()
+ {
+ $user = $this->addUser();
+ $this->addTagBookmark($user, array('one', 'two'));
+ $this->addTagBookmark($user, array('one', 'thr'));
+ $this->addTagBookmark($user, array('one', 'two'));
+ $this->addTagBookmark($user, array('one', 'thr'));
+
+ $arTags = $this->b2ts->getPopularTags(null, 10, null, null, 'o');
+ $this->assertEquals(1, count($arTags));
+ $this->assertContains(array('tag' => 'one', 'bCount' => '4'), $arTags);
+
+ $arTags = $this->b2ts->getPopularTags(null, 10, null, null, 'tw');
+ $this->assertEquals(1, count($arTags));
+ $this->assertContains(array('tag' => 'two', 'bCount' => '2'), $arTags);
+
+ $arTags = $this->b2ts->getPopularTags(null, 10, null, null, 't');
+ $this->assertEquals(2, count($arTags));
+ $this->assertContains(array('tag' => 'two', 'bCount' => '2'), $arTags);
+ $this->assertContains(array('tag' => 'thr', 'bCount' => '2'), $arTags);
+ }
+
+
+
+ /**
+ * @covers SemanticScuttle_Service_Bookmark2Tag::getPopularTags
+ */
+ public function testGetPopularTagsExcludesSystemTags()
+ {
+ $user = $this->addUser();
+ $this->addTagBookmark($user, array('one', 'system:test'));
+ $this->addTagBookmark($user, array('one', 'system:unittest'));
+ $this->addTagBookmark($user, array('one', 'sys:unittest'));
+
+ $arTags = $this->b2ts->getPopularTags();
+ $this->assertInternalType('array', $arTags);
+ $this->assertEquals(2, count($arTags));
+ $this->assertEquals(
+ array(
+ array('tag' => 'one', 'bCount' => '3'),
+ array('tag' => 'sys:unittest', 'bCount' => '1'),
+ ),
+ $arTags
+ );
+ }
+
+
+
+ /**
+ * @covers SemanticScuttle_Service_Bookmark2Tag::getPopularTags
+ */
+ public function testGetPopularTagsUserTags()
+ {
+ $user1 = $this->addUser();
+ $user2 = $this->addUser();
+ $user3 = $this->addUser();
+ $this->addTagBookmark($user1, array('one'));
+ $this->addTagBookmark($user2, array('one', 'two'));
+ $this->addTagBookmark($user2, array('two'));
+ $this->addTagBookmark($user3, array('one', 'thr'));
+
+ $arTags = $this->b2ts->getPopularTags($user1);
+ $this->assertEquals(1, count($arTags));
+ $this->assertEquals(
+ array(
+ array('tag' => 'one', 'bCount' => '1'),
+ ),
+ $arTags
+ );
+
+ $arTags = $this->b2ts->getPopularTags($user2);
+ $this->assertEquals(2, count($arTags));
+ $this->assertEquals(
+ array(
+ array('tag' => 'two', 'bCount' => '2'),
+ array('tag' => 'one', 'bCount' => '1'),
+ ),
+ $arTags
+ );
+
+ $arTags = $this->b2ts->getPopularTags(array($user2, $user3));
+ $this->assertEquals(3, count($arTags));
+ $this->assertContains(array('tag' => 'one', 'bCount' => '2'), $arTags);
+ $this->assertContains(array('tag' => 'two', 'bCount' => '2'), $arTags);
+ $this->assertContains(array('tag' => 'thr', 'bCount' => '1'), $arTags);
+ }
+
+
+
+ /**
+ * This may happen when the method is called with a problematic user array.
+ * In that case we may not generate invalid SQL or so.
+ *
+ * @covers SemanticScuttle_Service_Bookmark2Tag::getPopularTags
+ */
+ public function testGetPopularTagsUserArrayWithNull()
+ {
+ $user1 = $this->addUser();
+ $this->addTagBookmark($user1, array('one'));
+
+ $arTags = $this->b2ts->getPopularTags(array(null));
+ $this->assertEquals(0, count($arTags));
+ }
+
+
+
+ /**
+ * @covers SemanticScuttle_Service_Bookmark2Tag::getPopularTags
+ */
+ public function testGetPopularTagsPublicOnlyNoUser()
+ {
+ $user1 = $this->addUser();
+ $this->addBookmark($user1, null, 0, array('one'));
+ $this->addBookmark($user1, null, 1, array('one', 'two'));
+ $this->addBookmark($user1, null, 2, array('thr'));
+
+ $arTags = $this->b2ts->getPopularTags();
+ $this->assertEquals(1, count($arTags));
+ $this->assertEquals(
+ array(
+ array('tag' => 'one', 'bCount' => '1'),
+ ),
+ $arTags
+ );
+ }
+
+ /**
+ * @covers SemanticScuttle_Service_Bookmark2Tag::getPopularTags
+ */
+ public function testGetPopularTagsPublicOnlySingleUser()
+ {
+ $user1 = $this->addUser();
+ $this->addBookmark($user1, null, 0, array('one'));
+ $this->addBookmark($user1, null, 1, array('one', 'two'));
+ $this->addBookmark($user1, null, 2, array('thr'));
+
+ $arTags = $this->b2ts->getPopularTags($user1);
+ $this->assertEquals(1, count($arTags));
+ $this->assertEquals(
+ array(
+ array('tag' => 'one', 'bCount' => '1'),
+ ),
+ $arTags
+ );
+ }
+
+ /**
+ * @covers SemanticScuttle_Service_Bookmark2Tag::getPopularTags
+ */
+ public function testGetPopularTagsPublicOnlySeveralUsers()
+ {
+ $user1 = $this->addUser();
+ $user2 = $this->addUser();
+ $this->addBookmark($user1, null, 0, array('one'));
+ $this->addBookmark($user1, null, 1, array('one', 'two'));
+ $this->addBookmark($user1, null, 2, array('thr'));
+ $this->addBookmark($user2, null, 0, array('fou'));
+ $this->addBookmark($user2, null, 1, array('fiv'));
+ $this->addBookmark($user2, null, 2, array('six'));
+
+ $arTags = $this->b2ts->getPopularTags(array($user1, $user2));
+ $this->assertEquals(2, count($arTags));
+ $this->assertContains(array('tag' => 'one', 'bCount' => '1'), $arTags);
+ $this->assertContains(array('tag' => 'fou', 'bCount' => '1'), $arTags);
+ }
+
+ /**
+ * @covers SemanticScuttle_Service_Bookmark2Tag::getPopularTags
+ */
+ public function testGetPopularTagsUserPrivatesWhenLoggedIn()
+ {
+ $user1 = $this->addUser();
+ $this->addBookmark($user1, null, 0, array('one'));
+ $this->addBookmark($user1, null, 1, array('one', 'two'));
+ $this->addBookmark($user1, null, 2, array('thr'));
+
+ $arTags = $this->b2ts->getPopularTags($user1, 10, $user1);
+ $this->assertEquals(3, count($arTags));
+ $this->assertContains(array('tag' => 'one', 'bCount' => '2'), $arTags);
+ $this->assertContains(array('tag' => 'two', 'bCount' => '1'), $arTags);
+ $this->assertContains(array('tag' => 'thr', 'bCount' => '1'), $arTags);
+ }
+
+
+ /**
+ * @covers SemanticScuttle_Service_Bookmark2Tag::getAdminTags
+ */
+ public function testGetAdminTags()
+ {
+ $admin1 = $this->addUser('admin1');
+ $admin2 = $this->addUser('admin2');
+ $user1 = $this->addUser();
+ $this->addBookmark($admin1, null, 0, array('admintag', 'admintag1'));
+ $this->addBookmark($admin2, null, 0, array('admintag', 'admintag2'));
+ $this->addBookmark($user1, null, 0, array('usertag'));
+
+ $GLOBALS['admin_users'] = array('admin1', 'admin2');
+
+ $arTags = $this->b2ts->getAdminTags(4);
+ $this->assertEquals(3, count($arTags));
+ $this->assertContains(array('tag' => 'admintag', 'bCount' => '2'), $arTags);
+ $this->assertContains(array('tag' => 'admintag1', 'bCount' => '1'), $arTags);
+ $this->assertContains(array('tag' => 'admintag2', 'bCount' => '1'), $arTags);
+ }
+
+ /**
+ * @covers SemanticScuttle_Service_Bookmark2Tag::getAdminTags
+ */
+ public function testGetAdminTagsBeginsWith()
+ {
+ $admin1 = $this->addUser('admin1');
+ $this->addBookmark($admin1, null, 0, array('admintag', 'admintag1'));
+ $this->addBookmark($admin1, null, 0, array('tester', 'testos'));
+
+ $GLOBALS['admin_users'] = array('admin1');
+
+ $arTags = $this->b2ts->getAdminTags(4, null, null, 'test');
+ $this->assertEquals(2, count($arTags));
+ $this->assertContains(array('tag' => 'tester', 'bCount' => '1'), $arTags);
+ $this->assertContains(array('tag' => 'testos', 'bCount' => '1'), $arTags);
+ }
+
+
+
+ /**
+ * @covers SemanticScuttle_Service_Bookmark2Tag::getContactTags
+ */
+ public function testGetContactTagsWatchlistOnly()
+ {
+ $user1 = $this->addUser();
+ $user2 = $this->addUser();
+ $user3 = $this->addUser();
+ $this->us->setCurrentUserId($user1);
+ $this->us->setWatchStatus($user2);
+ //user1 watches user2 now
+
+ $this->addBookmark($user1, null, 0, array('usertag', 'usertag1'));
+ $this->addBookmark($user2, null, 0, array('usertag', 'usertag2'));
+ $this->addBookmark($user3, null, 0, array('usertag', 'usertag3'));
+
+ $arTags = $this->b2ts->getContactTags($user1, 10);
+ $this->assertEquals(2, count($arTags));
+ $this->assertContains(array('tag' => 'usertag', 'bCount' => '1'), $arTags);
+ $this->assertContains(array('tag' => 'usertag2', 'bCount' => '1'), $arTags);
+ }
+
+ /**
+ * @covers SemanticScuttle_Service_Bookmark2Tag::getContactTags
+ */
+ public function testGetContactTagsIncludingUser()
+ {
+ $user1 = $this->addUser();
+ $user2 = $this->addUser();
+ $user3 = $this->addUser();
+ $this->us->setCurrentUserId($user1);
+ $this->us->setWatchStatus($user2);
+ //user1 watches user2 now
+
+ $this->addBookmark($user1, null, 0, array('usertag', 'usertag1'));
+ $this->addBookmark($user2, null, 0, array('usertag', 'usertag2'));
+ $this->addBookmark($user3, null, 0, array('usertag', 'usertag3'));
+
+ $arTags = $this->b2ts->getContactTags($user1, 10, $user1);
+ $this->assertEquals(3, count($arTags));
+ $this->assertContains(array('tag' => 'usertag', 'bCount' => '2'), $arTags);
+ $this->assertContains(array('tag' => 'usertag1', 'bCount' => '1'), $arTags);
+ $this->assertContains(array('tag' => 'usertag2', 'bCount' => '1'), $arTags);
+ }
+
+ /**
+ * @covers SemanticScuttle_Service_Bookmark2Tag::getContactTags
+ */
+ public function testGetContactTagsBeginsWith()
+ {
+ $user1 = $this->addUser();
+ $this->addBookmark($user1, null, 0, array('usertag', 'usertag1'));
+ $this->addBookmark($user1, null, 0, array('usable', 'undefined'));
+ $this->addBookmark($user1, null, 0, array('fußbad', 'usable'));
+
+ $arTags = $this->b2ts->getContactTags($user1, 10, $user1, null, 'user');
+ $this->assertEquals(2, count($arTags));
+ $this->assertContains(array('tag' => 'usertag', 'bCount' => '1'), $arTags);
+ $this->assertContains(array('tag' => 'usertag1', 'bCount' => '1'), $arTags);
+
+ $arTags = $this->b2ts->getContactTags($user1, 10, $user1, null, 'us');
+ $this->assertEquals(3, count($arTags));
+ $this->assertContains(array('tag' => 'usertag', 'bCount' => '1'), $arTags);
+ $this->assertContains(array('tag' => 'usertag1', 'bCount' => '1'), $arTags);
+ $this->assertContains(array('tag' => 'usable', 'bCount' => '2'), $arTags);
+ }
}
if (PHPUnit_MAIN_METHOD == 'Bookmark2TagTest::main') {
diff --git a/tests/BookmarkTest.php b/tests/BookmarkTest.php
index 40869b2..f54fe9a 100644
--- a/tests/BookmarkTest.php
+++ b/tests/BookmarkTest.php
@@ -12,13 +12,12 @@
* @license GPL http://www.gnu.org/licenses/gpl.html
* @link http://sourceforge.net/projects/semanticscuttle
*/
-
-require_once 'prepare.php';
-
if (!defined('PHPUnit_MAIN_METHOD')) {
define('PHPUnit_MAIN_METHOD', 'BookmarkTest::main');
}
+require_once 'prepare.php';
+
/**
* Unit tests for the SemanticScuttle bookmark service.
*
@@ -264,7 +263,7 @@ class BookmarkTest extends TestBase
$bookmark = $this->bs->getBookmark($bid);
$ret = $this->bs->bookmarksExist(array($bookmark['bAddress']));
- $this->assertType('array', $ret);
+ $this->assertInternalType('array', $ret);
$this->assertEquals(1, count($ret));
$this->assertTrue($ret[$bookmark['bAddress']]);
}
@@ -292,7 +291,7 @@ class BookmarkTest extends TestBase
$bookmark2['bAddress']
)
);
- $this->assertType('array', $ret);
+ $this->assertInternalType('array', $ret);
$this->assertEquals(2, count($ret));
$this->assertTrue($ret[$bookmark['bAddress']]);
$this->assertTrue($ret[$bookmark2['bAddress']]);
@@ -309,7 +308,7 @@ class BookmarkTest extends TestBase
public function testBookmarksExistFalseSingle()
{
$ret = $this->bs->bookmarksExist(array('does-not-exist'));
- $this->assertType('array', $ret);
+ $this->assertInternalType('array', $ret);
$this->assertEquals(1, count($ret));
$this->assertFalse($ret['does-not-exist']);
}
@@ -330,7 +329,7 @@ class BookmarkTest extends TestBase
'does-not-exist-3',
);
$ret = $this->bs->bookmarksExist($bms);
- $this->assertType('array', $ret);
+ $this->assertInternalType('array', $ret);
$this->assertEquals(3, count($ret));
$this->assertFalse($ret['does-not-exist']);
$this->assertFalse($ret['does-not-exist-2']);
@@ -367,7 +366,7 @@ class BookmarkTest extends TestBase
'does-not-exist-3'
)
);
- $this->assertType('array', $ret);
+ $this->assertInternalType('array', $ret);
$this->assertEquals(5, count($ret));
$this->assertTrue($ret[$bookmark['bAddress']]);
$this->assertTrue($ret[$bookmark2['bAddress']]);
@@ -476,7 +475,7 @@ class BookmarkTest extends TestBase
foreach ($bms['bookmarks'] as $bm) {
$this->assertArrayHasKey('tags', $bm);
- $this->assertType('array', $bm['tags']);
+ $this->assertInternalType('array', $bm['tags']);
if ($bm['bId'] == $bid) {
$this->assertContains('foo', $bm['tags']);
$this->assertContains('bar', $bm['tags']);
@@ -757,7 +756,7 @@ class BookmarkTest extends TestBase
$bm = $this->bs->getBookmark($bid, true);
$this->assertArrayHasKey('tags', $bm);
- $this->assertType('array', $bm['tags']);
+ $this->assertInternalType('array', $bm['tags']);
$this->assertContains('foo', $bm['tags']);
$this->assertContains('bar', $bm['tags']);
}
@@ -875,7 +874,7 @@ class BookmarkTest extends TestBase
$bid = $this->addBookmark($uid, $url);
$bm = $this->bs->getBookmarkByAddress($url);
- $this->assertType('array', $bm);
+ $this->assertInternalType('array', $bm);
$this->assertEquals($url, $bm['bAddress']);
}
@@ -901,7 +900,7 @@ class BookmarkTest extends TestBase
$bid = $this->addBookmark($uid, $url);
$bm = $this->bs->getBookmarkByAddress($incomplete);
- $this->assertType('array', $bm);
+ $this->assertInternalType('array', $bm);
$this->assertEquals($url, $bm['bAddress']);
}
@@ -952,7 +951,7 @@ class BookmarkTest extends TestBase
$this->assertEquals('new description', $bm['bDescription']);
$this->assertEquals('new private note', $bm['bPrivateNote']);
$this->assertEquals(1, $bm['bStatus']);
- $this->assertType('array', $bm['tags']);
+ $this->assertInternalType('array', $bm['tags']);
$this->assertEquals(1, count($bm['tags']));
$this->assertContains('new', $bm['tags']);
}
@@ -982,6 +981,38 @@ class BookmarkTest extends TestBase
$this->assertEquals('newShortNambb', $bm['bShort']);
}
+ /**
+ * Tests if updating a bookmark's date works.
+ * This once was a bug, see bug #3073215.
+ *
+ * @return void
+ *
+ * @link https://sourceforge.net/tracker/?func=detail&atid=1017430&aid=3073215&group_id=211356
+ */
+ public function testUpdateBookmarkDate()
+ {
+ $bid = $this->bs->addBookmark(
+ 'http://example.org', 'title', 'desc', 'priv',
+ 0, array(), 'myShortName'
+ );
+ $bm = $this->bs->getBookmark($bid);
+ $this->assertEquals('myShortName', $bm['bShort']);
+
+ $this->assertTrue(
+ $this->bs->updateBookmark(
+ $bid, 'http://example2.org', 'my title', 'desc',
+ 'priv', 0, array(), 'newShortNambb',
+ //we need to use zulu (GMT) time zone here
+ // since the dates/times are stored as that
+ // in the database
+ '2002-03-04T05:06:07Z'
+ )
+ );
+ $bm = $this->bs->getBookmark($bid);
+ $this->assertEquals('newShortNambb', $bm['bShort']);
+ $this->assertEquals('2002-03-04 05:06:07', $bm['bDatetime']);
+ }
+
/**
@@ -1087,12 +1118,98 @@ class BookmarkTest extends TestBase
/**
* Test what countOther() returns when the user is logged in
+ * and a friend (people on the watchlist) has bookmarked
+ * and the same address with public status.
+ *
+ * @return void
+ */
+ public function testCountOthersWatchlistPublic()
+ {
+ $uid = $this->addUser();
+ $address = 'http://example.org';
+
+ //create other user and add main user to his watchlist
+ $friendPublic1 = $this->addUser();
+ $this->us->setCurrentUserId($friendPublic1);
+ $this->us->setWatchStatus($uid);
+
+ //create bookmarks for main user and other one
+ $this->addBookmark($uid, $address, 0);
+ $this->addBookmark($friendPublic1, $address, 0);//0 is public
+
+ //log main user in
+ $this->us->setCurrentUserId($uid);
+
+ $this->assertEquals(1, $this->bs->countOthers($address));
+ }
+
+
+
+ /**
+ * Test what countOther() returns when the user is logged in
+ * and a friend (people on the watchlist) has bookmarked
+ * and shared the same address for the watchlist.
+ *
+ * @return void
+ */
+ public function testCountOthersWatchlistShared()
+ {
+ $uid = $this->addUser();
+ $address = 'http://example.org';
+
+ //create other user and add main user to his watchlist
+ $friendPublic1 = $this->addUser();
+ $this->us->setCurrentUserId($friendPublic1);
+ $this->us->setWatchStatus($uid);
+
+ //create bookmarks for main user and other one
+ $this->addBookmark($uid, $address, 0);
+ $this->addBookmark($friendPublic1, $address, 1);//1 is shared
+
+ //log main user in
+ $this->us->setCurrentUserId($uid);
+
+ $this->assertEquals(1, $this->bs->countOthers($address));
+ }
+
+
+
+ /**
+ * Test what countOther() returns when the user is logged in
+ * and one friends (people on the watchlist) has bookmarked
+ * the same address but made it private.
+ *
+ * @return void
+ */
+ public function testCountOthersWatchlistPrivate()
+ {
+ $uid = $this->addUser();
+ $address = 'http://example.org';
+
+ //create other user and add main user to his watchlist
+ $friendPublic1 = $this->addUser();
+ $this->us->setCurrentUserId($friendPublic1);
+ $this->us->setWatchStatus($uid);
+
+ //create bookmarks for main user and other one
+ $this->addBookmark($uid, $address, 0);
+ $this->addBookmark($friendPublic1, $address, 2);//2 is private
+
+ //log main user in
+ $this->us->setCurrentUserId($uid);
+
+ $this->assertEquals(0, $this->bs->countOthers($address));
+ }
+
+
+ /**
+ * Test what countOther() returns when the user is logged in
* and friends (people on the watchlist) have bookmarked
* and shared the same address.
*
* @return void
*/
- public function testCountOthersWatchlist()
+ public function testCountOthersWatchlistComplex()
{
$uid = $this->addUser();
$address = 'http://example.org';
diff --git a/tests/CommonDescriptionTest.php b/tests/CommonDescriptionTest.php
index 63b9e0c..94f431d 100644
--- a/tests/CommonDescriptionTest.php
+++ b/tests/CommonDescriptionTest.php
@@ -12,13 +12,12 @@
* @license GPL http://www.gnu.org/licenses/gpl.html
* @link http://sourceforge.net/projects/semanticscuttle
*/
-
-require_once 'prepare.php';
-
if (!defined('PHPUnit_MAIN_METHOD')) {
define('PHPUnit_MAIN_METHOD', 'CommonDescriptionTest::main');
}
+require_once 'prepare.php';
+
/**
* Unit tests for the SemanticScuttle common description service.
*
diff --git a/tests/SearchHistoryTest.php b/tests/SearchHistoryTest.php
index 3716b37..69d1efa 100644
--- a/tests/SearchHistoryTest.php
+++ b/tests/SearchHistoryTest.php
@@ -12,13 +12,12 @@
* @license GPL http://www.gnu.org/licenses/gpl.html
* @link http://sourceforge.net/projects/semanticscuttle
*/
-
-require_once 'prepare.php';
-
if (!defined('PHPUnit_MAIN_METHOD')) {
define('PHPUnit_MAIN_METHOD', 'SearchHistoryTest::main');
}
+require_once 'prepare.php';
+
/**
* Unit tests for the SemanticScuttle search history service.
*
@@ -55,63 +54,341 @@ class SearchHistoryTest extends TestBase
+ /**
+ * Set up all services
+ *
+ * @return void
+ */
protected function setUp()
{
- $this->us =SemanticScuttle_Service_Factory::get('User');
- $this->bs =SemanticScuttle_Service_Factory::get('Bookmark');
- $this->bs->deleteAll();
- $this->b2ts =SemanticScuttle_Service_Factory::get('Bookmark2Tag');
- $this->b2ts->deleteAll();
- $this->tts =SemanticScuttle_Service_Factory::get('Tag2Tag');
- $this->tts->deleteAll();
- $this->tsts =SemanticScuttle_Service_Factory::get('TagStat');
- $this->tsts->deleteAll();
- $this->shs =SemanticScuttle_Service_Factory::get('SearchHistory');
- $this->shs->deleteAll();
- }
-
- public function testSearchHistory()
- {
- $shs = $this->shs;
-
- $terms = 'bbqsdkbb;,:,:q;,qddds&é"\'\\\\\(-è_çà)';
- $terms2 = '~#{|`]';
- $range = 'all';
- $nbResults = 10908;
- $uId = 10;
-
- $shs->addSearch($terms, $range, $nbResults, $uId);
- $shs->addSearch($terms2, $range, $nbResults, $uId);
- $shs->addSearch('', $range, $nbResults, $uId); // A void search must not be saved
-
- $searches = $shs->getAllSearches();
- $this->assertSame(2, count($searches));
- $searches = $shs->getAllSearches($range, $uId);
- $this->assertEquals(2, count($searches));
- $searches = $shs->getAllSearches($range, 20); // fake userid
- $this->assertEquals(0, count($searches));
- $searches = $shs->getAllSearches($range, $uId, 1);
- $this->assertEquals(1, count($searches));
- $searches = $shs->getAllSearches($range, null, 1, 1);
- $this->assertEquals(1, count($searches));
-
- //test content of results
- $searches = $shs->getAllSearches();
- $this->assertSame($terms2, $searches[0]['shTerms']);
- $this->assertSame($range, $searches[0]['shRange']);
- $this->assertEquals($nbResults, $searches[0]['shNbResults']);
- $this->assertEquals($uId, $searches[0]['uId']);
- $this->assertSame($terms, $searches[1]['shTerms']);
- $this->assertSame($range, $searches[1]['shRange']);
- $this->assertEquals($nbResults, $searches[1]['shNbResults']);
- $this->assertEquals($uId, $searches[1]['uId']);
-
- //test distinct parameter
- $shs->addSearch($terms, $range, $nbResults, 30); // we repeat a search (same terms)
- $searches = $shs->getAllSearches();
- $this->assertSame(3, count($searches));
- $searches = $shs->getAllSearches(NULL, NULL, NULL, NULL, true);
- $this->assertSame(2, count($searches));
+ $this->us = SemanticScuttle_Service_Factory::get('User');
+ $this->bs = SemanticScuttle_Service_Factory::get('Bookmark');
+ $this->bs->deleteAll();
+
+ $this->b2ts =SemanticScuttle_Service_Factory::get('Bookmark2Tag');
+ $this->b2ts->deleteAll();
+
+ $this->tts = SemanticScuttle_Service_Factory::get('Tag2Tag');
+ $this->tts->deleteAll();
+
+ $this->tsts = SemanticScuttle_Service_Factory::get('TagStat');
+ $this->tsts->deleteAll();
+
+ $this->shs = SemanticScuttle_Service_Factory::get('SearchHistory');
+ $this->shs->deleteAll();
+ }
+
+ /**
+ * Tests if adding searches to the database works
+ *
+ * @covers SemanticScuttle_Service_SearchHistory::addSearch
+ */
+ public function testAddSearch()
+ {
+ $this->assertEquals(0, $this->shs->countSearches());
+
+ $this->assertTrue(
+ $this->shs->addSearch('testsearchterm', 'all', 0)
+ );
+ $this->assertEquals(1, $this->shs->countSearches());
+ }
+
+ /**
+ * Tests if adding a search without terms should fail
+ *
+ * @covers SemanticScuttle_Service_SearchHistory::addSearch
+ */
+ public function testAddSearchNoTerms()
+ {
+ $this->assertEquals(0, $this->shs->countSearches());
+
+ $this->assertFalse(
+ $this->shs->addSearch('', 'all', 0)
+ );
+ $this->assertEquals(0, $this->shs->countSearches());
+ }
+
+ /**
+ * Tests if adding a search deletes the history if it is too
+ * large.
+ *
+ * @covers SemanticScuttle_Service_SearchHistory::addSearch
+ */
+ public function testAddSearchDeleteHistory()
+ {
+ $this->assertEquals(0, $this->shs->countSearches());
+
+ $this->shs->sizeSearchHistory = 5;
+ $this->shs->addSearch('eins', 'all', 1);
+ $this->shs->addSearch('zwei', 'all', 1);
+ $this->shs->addSearch('drei', 'all', 1);
+ $this->shs->addSearch('view', 'all', 1);
+ $this->shs->addSearch('fünf', 'all', 1);
+ $this->assertEquals(5, $this->shs->countSearches());
+
+ $this->shs->addSearch('sechs', 'all', 1);
+ $this->assertEquals(5, $this->shs->countSearches());
+
+ $this->shs->sizeSearchHistory = 6;
+ $this->shs->addSearch('sieben', 'all', 1);
+ $this->assertEquals(6, $this->shs->countSearches());
+ $this->shs->addSearch('acht', 'all', 1);
+ $this->assertEquals(6, $this->shs->countSearches());
+ }
+
+ /**
+ * Test getAllSearches() without any parameters
+ */
+ public function testGetAllSearches()
+ {
+ $this->assertEquals(0, $this->shs->countSearches());
+
+ $this->shs->addSearch('eins', 'all', 1);
+ $this->shs->addSearch('zwei', 'all', 1);
+ $this->shs->addSearch('drei', 'all', 1);
+
+ $rows = $this->shs->getAllSearches();
+ $this->assertEquals(3, count($rows));
+
+ $terms = array();
+ foreach ($rows as $row) {
+ $terms[] = $row['shTerms'];
+ }
+ sort($terms);
+ $this->assertEquals(
+ array('drei', 'eins', 'zwei'),
+ $terms
+ );
+ }
+
+ /**
+ * Test getAllSearches() return value row array keys.
+ */
+ public function testGetAllSearchesTypes()
+ {
+ $this->assertEquals(0, $this->shs->countSearches());
+
+ $this->shs->addSearch('eins', 'all', 1);
+
+ $rows = $this->shs->getAllSearches();
+ $this->assertEquals(1, count($rows));
+ $row = reset($rows);
+
+ $this->assertArrayHasKey('shTerms', $row);
+ $this->assertArrayHasKey('shId', $row);
+ $this->assertArrayHasKey('shRange', $row);
+ $this->assertArrayHasKey('shNbResults', $row);
+ $this->assertArrayHasKey('shDatetime', $row);
+ $this->assertArrayHasKey('uId', $row);
+ }
+
+ /**
+ * Test getAllSearches() range parameter
+ */
+ public function testGetAllSearchesRange()
+ {
+ $this->assertEquals(0, $this->shs->countSearches());
+
+ $this->shs->addSearch('eins', 'all', 1);
+ $this->shs->addSearch('zwei', 'watchlist', 1);
+ $this->shs->addSearch('drei', 'watchlist', 1);
+ $this->shs->addSearch('vier', 'user1', 1);
+ $this->shs->addSearch('fünf', 'user2', 1);
+
+ $rows = $this->shs->getAllSearches('all');
+ $this->assertEquals(1, count($rows));
+
+ $rows = $this->shs->getAllSearches('watchlist');
+ $this->assertEquals(2, count($rows));
+
+ $rows = $this->shs->getAllSearches('user0');
+ $this->assertEquals(0, count($rows));
+
+ $rows = $this->shs->getAllSearches('user1');
+ $this->assertEquals(1, count($rows));
+ $this->assertEquals('vier', $rows[0]['shTerms']);
+ }
+
+ /**
+ * Test getAllSearches() uId parameter
+ */
+ public function testGetAllSearchesUid()
+ {
+ $this->assertEquals(0, $this->shs->countSearches());
+
+ $this->shs->addSearch('eins', 'all', 1, 0);
+ $this->shs->addSearch('zwei', 'all', 1, 0);
+ $this->shs->addSearch('drei', 'all', 1, 1);
+
+ $rows = $this->shs->getAllSearches(null, null);
+ $this->assertEquals(3, count($rows));
+
+ $rows = $this->shs->getAllSearches(null, 1);
+ $this->assertEquals(1, count($rows));
+ $this->assertEquals('drei', $rows[0]['shTerms']);
+ }
+
+ /**
+ * Test getAllSearches() number parameter
+ */
+ public function testGetAllSearchesNb()
+ {
+ $this->assertEquals(0, $this->shs->countSearches());
+
+ $this->shs->addSearch('eins', 'all', 1, 0);
+ $this->shs->addSearch('zwei', 'all', 1, 0);
+ $this->shs->addSearch('drei', 'all', 1, 1);
+
+ $rows = $this->shs->getAllSearches(null, null, 1);
+ $this->assertEquals(1, count($rows));
+
+ $rows = $this->shs->getAllSearches(null, null, 2);
+ $this->assertEquals(2, count($rows));
+
+ $rows = $this->shs->getAllSearches(null, null, 3);
+ $this->assertEquals(3, count($rows));
+
+ $rows = $this->shs->getAllSearches(null, null, 4);
+ $this->assertEquals(3, count($rows));
+ }
+
+ /**
+ * Test getAllSearches() paging start parameter
+ */
+ public function testGetAllSearchesStart()
+ {
+ $this->assertEquals(0, $this->shs->countSearches());
+
+ $this->shs->addSearch('eins', 'all', 1, 0);
+ $this->shs->addSearch('zwei', 'all', 1, 0);
+ $this->shs->addSearch('drei', 'all', 1, 1);
+
+ $rows = $this->shs->getAllSearches(null, null, 1, 0);
+ $this->assertEquals(1, count($rows));
+ $this->assertEquals('drei', $rows[0]['shTerms']);
+
+ $rows = $this->shs->getAllSearches(null, null, 1, 1);
+ $this->assertEquals(1, count($rows));
+ $this->assertEquals('zwei', $rows[0]['shTerms']);
+
+ $rows = $this->shs->getAllSearches(null, null, 3, 2);
+ $this->assertEquals(1, count($rows));
+ $this->assertEquals('eins', $rows[0]['shTerms']);
+ }
+
+ /**
+ * Test getAllSearches() distinct parameter
+ */
+ public function testGetAllSearchesDistinct()
+ {
+ $this->assertEquals(0, $this->shs->countSearches());
+
+ $this->shs->addSearch('eins', 'all', 1);
+ $this->shs->addSearch('eins', 'all', 1);
+ $this->shs->addSearch('drei', 'all', 1);
+
+ $rows = $this->shs->getAllSearches(null, null, null, null, false);
+ $this->assertEquals(3, count($rows));
+
+ $rows = $this->shs->getAllSearches(null, null, null, null, true);
+ $this->assertEquals(2, count($rows));
+ }
+
+ /**
+ * Test getAllSearches() withResults parameter
+ */
+ public function testGetAllSearchesWithResults()
+ {
+ $this->assertEquals(0, $this->shs->countSearches());
+
+ $this->shs->addSearch('eins', 'all', 0);
+ $this->shs->addSearch('zwei', 'all', 0);
+ $this->shs->addSearch('drei', 'all', 1);
+
+ $rows = $this->shs->getAllSearches(null, null, null, null, false, false);
+ $this->assertEquals(3, count($rows));
+
+ $rows = $this->shs->getAllSearches(null, null, null, null, false, true);
+ $this->assertEquals(1, count($rows));
+ }
+
+ /**
+ * Deleting the oldest search without any historical searches
+ *
+ * @covers SemanticScuttle_Service_SearchHistory::deleteOldestSearch
+ */
+ public function testDeleteOldestSearchNone()
+ {
+ $this->assertEquals(0, $this->shs->countSearches());
+ $this->assertTrue($this->shs->deleteOldestSearch());
+ $this->assertEquals(0, $this->shs->countSearches());
+ }
+
+ /**
+ * Test deleting the oldest search
+ *
+ * @covers SemanticScuttle_Service_SearchHistory::deleteOldestSearch
+ */
+ public function testDeleteOldestSearchSome()
+ {
+ $this->assertEquals(0, $this->shs->countSearches());
+ $this->shs->addSearch('testsearchterm1', 'all', 0);
+ $this->shs->addSearch('testsearchterm2', 'all', 0);
+
+ $rows = $this->shs->getAllSearches();
+ $this->assertEquals(2, count($rows));
+
+ $highestId = -1;
+ foreach ($rows as $row) {
+ if ($row['shId'] > $highestId) {
+ $highestId = $row['shId'];
+ }
+ }
+
+ $this->shs->deleteOldestSearch();
+
+ $this->assertEquals(1, $this->shs->countSearches());
+
+ $rows = $this->shs->getAllSearches();
+ $this->assertEquals(1, count($rows));
+ $this->assertEquals(
+ $highestId,
+ $rows[0]['shId']
+ );
+ }
+
+ /**
+ * Test if deleting the search history for a certain user works
+ */
+ public function testDeleteSearchHistoryForUser()
+ {
+ $this->assertEquals(0, $this->shs->countSearches());
+
+ $this->shs->addSearch('eins', 'all', 1, 0);
+ $this->shs->addSearch('zwei', 'all', 1, 22);
+ $this->shs->addSearch('drei', 'all', 1, 1);
+ $this->shs->addSearch('vier', 'all', 1, 22);
+
+ $this->shs->deleteSearchHistoryForUser(22);
+ $this->assertEquals(2, $this->shs->countSearches());
+
+ $this->shs->deleteSearchHistoryForUser(20);
+ $this->assertEquals(2, $this->shs->countSearches());
+
+ $this->shs->deleteSearchHistoryForUser(1);
+ $this->assertEquals(1, $this->shs->countSearches());
+ }
+
+
+ /**
+ * Test deleting all of the search history
+ */
+ public function testDeleteAll()
+ {
+ $this->shs->addSearch('testsearchterm1', 'all', 0);
+ $this->shs->addSearch('testsearchterm2', 'all', 0);
+ $this->shs->deleteAll();
+ $this->assertEquals(0, $this->shs->countSearches());
}
}
diff --git a/tests/Tag2TagTest.php b/tests/Tag2TagTest.php
index d1b6100..033fc91 100644
--- a/tests/Tag2TagTest.php
+++ b/tests/Tag2TagTest.php
@@ -12,13 +12,12 @@
* @license GPL http://www.gnu.org/licenses/gpl.html
* @link http://sourceforge.net/projects/semanticscuttle
*/
-
-require_once 'prepare.php';
-
if (!defined('PHPUnit_MAIN_METHOD')) {
define('PHPUnit_MAIN_METHOD', 'Tag2TagTest::main');
}
+require_once 'prepare.php';
+
/**
* Unit tests for the SemanticScuttle tag2tag service.
*
diff --git a/tests/TagTest.php b/tests/TagTest.php
index c08aba2..25d1a77 100644
--- a/tests/TagTest.php
+++ b/tests/TagTest.php
@@ -12,13 +12,12 @@
* @license GPL http://www.gnu.org/licenses/gpl.html
* @link http://sourceforge.net/projects/semanticscuttle
*/
-
-require_once 'prepare.php';
-
if (!defined('PHPUnit_MAIN_METHOD')) {
define('PHPUnit_MAIN_METHOD', 'TagTest::main');
}
+require_once 'prepare.php';
+
/**
* Unit tests for the SemanticScuttle tag service.
*
diff --git a/tests/TagsCacheTest.php b/tests/TagsCacheTest.php
index 9097bcb..94200dd 100644
--- a/tests/TagsCacheTest.php
+++ b/tests/TagsCacheTest.php
@@ -12,13 +12,12 @@
* @license GPL http://www.gnu.org/licenses/gpl.html
* @link http://sourceforge.net/projects/semanticscuttle
*/
-
-require_once 'prepare.php';
-
if (!defined('PHPUnit_MAIN_METHOD')) {
define('PHPUnit_MAIN_METHOD', 'TagsCacheTest::main');
}
+require_once 'prepare.php';
+
/**
* Unit tests for the SemanticScuttle tags cache service.
*
@@ -54,9 +53,6 @@ class TagsCacheTest extends PHPUnit_Framework_TestCase
protected function setUp()
{
- global $dbhost, $dbuser, $dbpass, $dbname, $dbport, $dbpersist, $dbtype, $tableprefix, $TEMPLATES_DIR, $debugMode;
- require_once dirname(__FILE__) . '/../src/SemanticScuttle/header.php';
-
$this->us =SemanticScuttle_Service_Factory::get('User');
$this->bs =SemanticScuttle_Service_Factory::get('Bookmark');
$this->bs->deleteAll();
diff --git a/tests/TestBase.php b/tests/TestBase.php
index 402330b..095f32d 100644
--- a/tests/TestBase.php
+++ b/tests/TestBase.php
@@ -11,10 +11,6 @@
* @link http://sourceforge.net/projects/semanticscuttle
*/
-require_once 'PHPUnit/Framework.php';
-
-PHPUnit_Util_Filter::addFileToFilter(__FILE__);
-
/**
* Base unittest class that provides several helper methods.
*
@@ -35,6 +31,7 @@ class TestBase extends PHPUnit_Framework_TestCase
* @param array $tags Array of tags to attach. If "null" is given,
* it will automatically be "unittest"
* @param string $title Bookmark title
+ * @param string $date strtotime-compatible string
*
* @return integer ID of bookmark
*
@@ -42,7 +39,7 @@ class TestBase extends PHPUnit_Framework_TestCase
*/
protected function addBookmark(
$user = null, $address = null, $status = 0,
- $tags = null, $title = null
+ $tags = null, $title = null, $date = null
) {
if ($user === null) {
$user = $this->addUser();
@@ -68,7 +65,7 @@ class TestBase extends PHPUnit_Framework_TestCase
null,
$status,
$tags,
- null, null, false, false,
+ null, $date, false, false,
$user
);
return $bid;
@@ -83,9 +80,26 @@ class TestBase extends PHPUnit_Framework_TestCase
* @param string $password Password
*
* @return integer ID of user
+ *
+ * @uses addUserData()
*/
protected function addUser($username = null, $password = null)
{
+ return reset($this->addUserData($username, $password));
+ }
+
+
+
+ /**
+ * Creates a new user in the database and returns id, username and password.
+ *
+ * @param string $username Username
+ * @param string $password Password
+ *
+ * @return array ID of user, Name of user, password of user
+ */
+ protected function addUserData($username = null, $password = null)
+ {
$us = SemanticScuttle_Service_Factory::get('User');
$rand = rand();
@@ -101,9 +115,37 @@ class TestBase extends PHPUnit_Framework_TestCase
$password,
'unittest-' . $rand . '@example.org'
);
- return $uid;
+ return array($uid, $username, $password);
}
+
+
+ /**
+ * Retrieves the UID of an admin user.
+ * If that user does not exist in the database, it is created.
+ *
+ * @return integer UID of admin user
+ */
+ protected function getAdminUser()
+ {
+ if (count($GLOBALS['admin_users']) == 0) {
+ $this->fail('No admin users configured');
+ }
+ $adminUserName = reset($GLOBALS['admin_users']);
+
+ $us = SemanticScuttle_Service_Factory::get('User');
+ $uid = $us->getIdFromUser($adminUserName);
+ if ($uid === null) {
+ //that user does not exist in the database; create it
+ $uid = $us->addUser(
+ $adminUserName,
+ rand(),
+ 'unittest-admin-' . $adminUserName . '@example.org'
+ );
+ }
+
+ return $uid;
+ }
}
?> \ No newline at end of file
diff --git a/tests/TestBaseApi.php b/tests/TestBaseApi.php
index 645ead9..f054973 100644
--- a/tests/TestBaseApi.php
+++ b/tests/TestBaseApi.php
@@ -11,10 +11,6 @@
* @link http://sourceforge.net/projects/semanticscuttle
*/
-require_once 'PHPUnit/Framework.php';
-
-PHPUnit_Util_Filter::addFileToFilter(__FILE__);
-
/**
* Base unittest class for web API tests.
*
@@ -29,6 +25,16 @@ class TestBaseApi extends TestBase
protected $url;
protected $urlPart = null;
+ /**
+ * @var SemanticScuttle_Service_User
+ */
+ protected $us;
+
+ /**
+ * @var SemanticScuttle_Service_Bookmark
+ */
+ protected $bs;
+
protected function setUp()
@@ -52,11 +58,26 @@ class TestBaseApi extends TestBase
/**
- * Gets a HTTP request object
+ * Clean up after test
+ */
+ public function tearDown()
+ {
+ if (file_exists($GLOBALS['datadir'] . '/config.unittest.php')) {
+ unlink($GLOBALS['datadir'] . '/config.unittest.php');
+ }
+ }
+
+
+
+ /**
+ * Gets a HTTP request object.
+ * Uses $this->url plus $urlSuffix as request URL.
*
* @param string $urlSuffix Suffix for the URL
*
* @return HTTP_Request2 HTTP request object
+ *
+ * @uses $url
*/
protected function getRequest($urlSuffix = null)
{
@@ -71,13 +92,20 @@ class TestBaseApi extends TestBase
/**
- * Gets a HTTP request object
+ * Creates a user and a HTTP request object and prepares
+ * the request object with authentication details, so that
+ * the user is logged in.
+ *
+ * Useful for HTTP API methods only, cannot be used with
+ * "normal" HTML pages since they do not support HTTP auth.
*
* @param string $urlSuffix Suffix for the URL
* @param mixed $auth If user authentication is needed (true/false)
* or array with username and password
*
* @return array(HTTP_Request2, integer) HTTP request object and user id
+ *
+ * @uses getRequest()
*/
protected function getAuthRequest($urlSuffix = null, $auth = true)
{
@@ -96,5 +124,102 @@ class TestBaseApi extends TestBase
return array($req, $uid);
}
+
+
+ /**
+ * Creates a user and a HTTP_Request2 object, does a normal login
+ * and prepares the cookies for the HTTP request object so that
+ * the user is seen as logged in when requesting any HTML page.
+ *
+ * Useful for testing HTML pages or ajax URLs.
+ *
+ * @param string $urlSuffix Suffix for the URL
+ * @param mixed $auth If user authentication is needed (true/false)
+ * or array with username and password
+ *
+ * @return array(HTTP_Request2, integer) HTTP request object and user id
+ *
+ * @uses getRequest()
+ */
+ protected function getLoggedInRequest($urlSuffix = null, $auth = true)
+ {
+ if (is_array($auth)) {
+ list($username, $password) = $auth;
+ } else {
+ $username = 'testuser';
+ $password = 'testpassword';
+ }
+ $uid = $this->addUser($username, $password);
+
+ $req = new HTTP_Request2(
+ $GLOBALS['unittestUrl'] . '/login.php',
+ HTTP_Request2::METHOD_POST
+ );
+ $cookies = $req->setCookieJar()->getCookieJar();
+ $req->addPostParameter('username', $username);
+ $req->addPostParameter('password', $password);
+ $req->addPostParameter('submitted', 'Log In');
+ $res = $req->send();
+
+ //after login, we normally get redirected
+ $this->assertEquals(302, $res->getStatus(), 'Login failure');
+
+ $req = $this->getRequest($urlSuffix);
+ $req->setCookieJar($cookies);
+
+ return array($req, $uid);
+ }
+
+
+
+ /**
+ * Verifies that the HTTP response has status code 200 and
+ * content-type application/json; charset=utf-8
+ *
+ * @param HTTP_Request2_Response $res HTTP Response object
+ *
+ * @return void
+ */
+ protected function assertResponseJson200(HTTP_Request2_Response $res)
+ {
+ $this->assertEquals(200, $res->getStatus());
+ $this->assertEquals(
+ 'application/json; charset=utf-8',
+ $res->getHeader('content-type')
+ );
+ }
+
+
+
+ /**
+ * Writes a special unittest configuration file.
+ * The unittest config file is read when a GET request with unittestMode=1
+ * is sent, and the user allowed unittestmode in config.php.
+ *
+ * @param array $arConfig Array with config names as key and their value as
+ * value
+ *
+ * @return void
+ */
+ protected function setUnittestConfig($arConfig)
+ {
+ $str = '<' . "?php\r\n";
+ foreach ($arConfig as $name => $value) {
+ $str .= '$' . $name . ' = '
+ . var_export($value, true) . ";\n";
+ }
+
+ if (!is_dir($GLOBALS['datadir'])) {
+ $this->fail(
+ 'datadir not set or not a directory: ' . $GLOBALS['datadir']
+ );
+ }
+
+ $this->assertInternalType(
+ 'integer',
+ file_put_contents($GLOBALS['datadir'] . '/config.unittest.php', $str),
+ 'Writing config.unittest.php failed'
+ );
+ }
}
?> \ No newline at end of file
diff --git a/tests/UserArrayTest.php b/tests/UserArrayTest.php
new file mode 100644
index 0000000..cb53f15
--- /dev/null
+++ b/tests/UserArrayTest.php
@@ -0,0 +1,68 @@
+<?php
+/**
+ * SemanticScuttle - your social bookmark manager.
+ *
+ * PHP version 5.
+ *
+ * @category Bookmarking
+ * @package SemanticScuttle
+ * @author Christian Weiske <cweiske@cweiske.de>
+ * @license GPL http://www.gnu.org/licenses/gpl.html
+ * @link http://sourceforge.net/projects/semanticscuttle
+ */
+
+require_once 'prepare.php';
+
+/**
+ * Unit tests for the SemanticScuttle user array model.
+ *
+ * @category Bookmarking
+ * @package SemanticScuttle
+ * @author Christian Weiske <cweiske@cweiske.de>
+ * @license GPL http://www.gnu.org/licenses/gpl.html
+ * @link http://sourceforge.net/projects/semanticscuttle
+ */
+class UserArrayTest extends PHPUnit_Framework_TestCase
+{
+
+ public function testGetNameLongName()
+ {
+ $this->assertEquals(
+ 'John Doe',
+ SemanticScuttle_Model_UserArray::getName(
+ array(
+ 'name' => 'John Doe',
+ 'username' => 'jdoe'
+ )
+ )
+ );
+ }
+
+ public function testGetNameUsernameIfNameIsEmpty()
+ {
+ $this->assertEquals(
+ 'jdoe',
+ SemanticScuttle_Model_UserArray::getName(
+ array(
+ 'name' => '',
+ 'username' => 'jdoe'
+ )
+ )
+ );
+ }
+
+ public function testGetNameUsernameIfNameIsNotSet()
+ {
+ $this->assertEquals(
+ 'jdoe',
+ SemanticScuttle_Model_UserArray::getName(
+ array(
+ 'username' => 'jdoe'
+ )
+ )
+ );
+ }
+
+}
+
+?> \ No newline at end of file
diff --git a/tests/UserTest.php b/tests/UserTest.php
index 18870c8..f0a7427 100644
--- a/tests/UserTest.php
+++ b/tests/UserTest.php
@@ -12,13 +12,12 @@
* @license GPL http://www.gnu.org/licenses/gpl.html
* @link http://sourceforge.net/projects/semanticscuttle
*/
-
-require_once 'prepare.php';
-
if (!defined('PHPUnit_MAIN_METHOD')) {
define('PHPUnit_MAIN_METHOD', 'UserTest::main');
}
+require_once 'prepare.php';
+
/**
* Unit tests for the SemanticScuttle user service.
*
@@ -211,7 +210,7 @@ class UserTest extends TestBase
$uid = $this->addUser();
$users = $this->us->getObjectUsers();
$this->assertEquals(1, count($users));
- $this->assertType('SemanticScuttle_Model_User', reset($users));
+ $this->assertInstanceOf('SemanticScuttle_Model_User', reset($users));
}
@@ -228,7 +227,7 @@ class UserTest extends TestBase
$uid3 = $this->addUser();
$users = $this->us->getObjectUsers();
$this->assertEquals(3, count($users));
- $this->assertType('SemanticScuttle_Model_User', reset($users));
+ $this->assertInstanceOf('SemanticScuttle_Model_User', reset($users));
}
diff --git a/tests/VoteTest.php b/tests/VoteTest.php
index 8e65917..1623826 100644
--- a/tests/VoteTest.php
+++ b/tests/VoteTest.php
@@ -10,13 +10,12 @@
* @license GPL http://www.gnu.org/licenses/gpl.html
* @link http://sourceforge.net/projects/semanticscuttle
*/
-
-require_once 'prepare.php';
-
if (!defined('PHPUnit_MAIN_METHOD')) {
define('PHPUnit_MAIN_METHOD', 'VoteTest::main');
}
+require_once 'prepare.php';
+
/**
* Unit tests for the SemanticScuttle voting system.
*
diff --git a/tests/ajax/GetAdminLinkedTagsTest.php b/tests/ajax/GetAdminLinkedTagsTest.php
new file mode 100644
index 0000000..aded834
--- /dev/null
+++ b/tests/ajax/GetAdminLinkedTagsTest.php
@@ -0,0 +1,146 @@
+<?php
+/**
+ * SemanticScuttle - your social bookmark manager.
+ *
+ * PHP version 5.
+ *
+ * @category Bookmarking
+ * @package SemanticScuttle
+ * @author Benjamin Huynh-Kim-Bang <mensonge@users.sourceforge.net>
+ * @author Christian Weiske <cweiske@cweiske.de>
+ * @author Eric Dane <ericdane@users.sourceforge.net>
+ * @license GPL http://www.gnu.org/licenses/gpl.html
+ * @link http://sourceforge.net/projects/semanticscuttle
+ */
+
+require_once dirname(__FILE__) . '/../prepare.php';
+require_once 'HTTP/Request2.php';
+
+if (!defined('PHPUnit_MAIN_METHOD')) {
+ define('PHPUnit_MAIN_METHOD', 'ajax_GetAdminLinkedTagsTest::main');
+}
+
+/**
+ * Unit tests for the ajax linked admin tags script
+ *
+ * @category Bookmarking
+ * @package SemanticScuttle
+ * @author Christian Weiske <cweiske@cweiske.de>
+ * @license GPL http://www.gnu.org/licenses/gpl.html
+ * @link http://sourceforge.net/projects/semanticscuttle
+ */
+class ajax_GetAdminLinkedTagsTest extends TestBaseApi
+{
+ protected $urlPart = 'ajax/getadminlinkedtags.php';
+
+
+
+ /**
+ * Used to run this test class standalone
+ *
+ * @return void
+ */
+ public static function main()
+ {
+ require_once 'PHPUnit/TextUI/TestRunner.php';
+ PHPUnit_TextUI_TestRunner::run(
+ new PHPUnit_Framework_TestSuite(__CLASS__)
+ );
+ }
+
+
+
+ /**
+ * Verify that we get the configured root tags if
+ * we do not pass any parameters
+ */
+ public function testRootTags()
+ {
+ $req = $this->getRequest();
+ $res = $req->send();
+ $this->assertResponseJson200($res);
+ $data = json_decode($res->getBody());
+ $this->assertInternalType('array', $data);
+
+ //same number of elements as the menu2Tags array
+ $this->assertEquals(
+ count($GLOBALS['menu2Tags']),
+ count($data)
+ );
+
+ //and the same contents
+ foreach ($data as $tagObj) {
+ $tagName = $tagObj->data->title;
+ $this->assertContains($tagName, $GLOBALS['menu2Tags']);
+ }
+ }
+
+ /**
+ * Verify that we get subtags of a given tag
+ */
+ public function testSubTags()
+ {
+ $t2t = SemanticScuttle_Service_Factory::get('Tag2Tag');
+ $t2t->deleteAll();
+
+ $menu2Tag = reset($GLOBALS['menu2Tags']);
+ //we have a subtag now
+ $this->addBookmark(
+ $this->getAdminUser(),
+ null,
+ 0,
+ $menu2Tag . '>adminsubtag'
+ );
+
+ $res = $this->getRequest('?tag=' . $menu2Tag)->send();
+ $this->assertResponseJson200($res);
+
+ $data = json_decode($res->getBody());
+ $this->assertInternalType('array', $data);
+
+ //only one subtag
+ $this->assertEquals(1, count($data));
+ $this->assertEquals('adminsubtag', $data[0]->data->title);
+ }
+
+ /**
+ * Verify that we only get admin tags, not tags from
+ * non-admin people
+ */
+ public function testOnlyAdminTags()
+ {
+ $t2t = SemanticScuttle_Service_Factory::get('Tag2Tag');
+ $t2t->deleteAll();
+
+ $menu2Tag = reset($GLOBALS['menu2Tags']);
+ //we have a subtag now
+ $this->addBookmark(
+ $this->getAdminUser(),
+ null,
+ 0,
+ $menu2Tag . '>adminsubtag'
+ );
+ //add another bookmark now, but for a normal user
+ $this->addBookmark(
+ null,
+ null,
+ 0,
+ $menu2Tag . '>normalsubtag'
+ );
+
+ $res = $this->getRequest('?tag=' . $menu2Tag)->send();
+ $this->assertResponseJson200($res);
+
+ $data = json_decode($res->getBody());
+ $this->assertInternalType('array', $data);
+
+ //we should have only one subtag now, the admin one
+ $this->assertEquals(1, count($data));
+ $this->assertEquals('adminsubtag', $data[0]->data->title);
+ }
+}
+
+if (PHPUnit_MAIN_METHOD == 'ajax_GetAdminLinkedTagsTest::main') {
+ ajax_GetAdminLinkedTagsTest::main();
+}
+?> \ No newline at end of file
diff --git a/tests/ajax/GetAdminTagsTest.php b/tests/ajax/GetAdminTagsTest.php
new file mode 100644
index 0000000..80d702f
--- /dev/null
+++ b/tests/ajax/GetAdminTagsTest.php
@@ -0,0 +1,122 @@
+<?php
+/**
+ * SemanticScuttle - your social bookmark manager.
+ *
+ * PHP version 5.
+ *
+ * @category Bookmarking
+ * @package SemanticScuttle
+ * @author Benjamin Huynh-Kim-Bang <mensonge@users.sourceforge.net>
+ * @author Christian Weiske <cweiske@cweiske.de>
+ * @author Eric Dane <ericdane@users.sourceforge.net>
+ * @license GPL http://www.gnu.org/licenses/gpl.html
+ * @link http://sourceforge.net/projects/semanticscuttle
+ */
+
+require_once dirname(__FILE__) . '/../prepare.php';
+require_once 'HTTP/Request2.php';
+
+/**
+ * Unit tests for the ajax getadmintags.php script
+ *
+ * @category Bookmarking
+ * @package SemanticScuttle
+ * @author Christian Weiske <cweiske@cweiske.de>
+ * @license GPL http://www.gnu.org/licenses/gpl.html
+ * @link http://sourceforge.net/projects/semanticscuttle
+ */
+class ajax_GetAdminTagsTest extends TestBaseApi
+{
+ protected $urlPart = 'ajax/getadmintags.php';
+
+
+ public function testTags()
+ {
+ list($user1, $uname1) = $this->addUserData();
+ $user2 = $this->addUser();
+ $this->addBookmark($user1, null, 0, array('admintag', 'admintag2'));
+ $this->addBookmark($user2, null, 0, array('lusertag', 'lusertag2'));
+
+ $this->setUnittestConfig(
+ array(
+ 'admin_users' => array($uname1)
+ )
+ );
+
+ $req = $this->getRequest('?unittestMode=1');
+ $res = $req->send();
+ $this->assertResponseJson200($res);
+ $data = json_decode($res->getBody());
+ $this->assertInternalType('array', $data);
+ $this->assertEquals(2, count($data));
+ $this->assertContains('admintag', $data);
+ $this->assertContains('admintag2', $data);
+ }
+
+ public function testParameterBeginsWith()
+ {
+ list($user1, $uname1) = $this->addUserData();
+ $this->addBookmark($user1, null, 0, array('foo', 'foobar', 'bar'));
+
+ $this->setUnittestConfig(
+ array(
+ 'admin_users' => array($uname1)
+ )
+ );
+
+ $req = $this->getRequest('?unittestMode=1&beginsWith=foo');
+ $res = $req->send();
+ $data = json_decode($res->getBody());
+ $this->assertResponseJson200($res);
+ $this->assertInternalType('array', $data);
+ $this->assertEquals(2, count($data));
+ $this->assertContains('foo', $data);
+ $this->assertContains('foobar', $data);
+ }
+
+
+
+ public function testParameterLimit()
+ {
+ list($user1, $uname1) = $this->addUserData();
+ list($user2, $uname2) = $this->addUserData();
+ $this->addBookmark($user1, null, 0, array('foo', 'foobar'));
+ $this->addBookmark($user2, null, 0, array('foo', 'bar'));
+
+ $this->setUnittestConfig(
+ array(
+ 'admin_users' => array($uname1, $uname2)
+ )
+ );
+
+ $req = $this->getRequest('?unittestMode=1&limit=1');
+ $res = $req->send();
+ $this->assertResponseJson200($res);
+ $data = json_decode($res->getBody());
+ $this->assertInternalType('array', $data);
+ $this->assertEquals(1, count($data));
+ $this->assertContains('foo', $data);
+
+ $req = $this->getRequest('?unittestMode=1&limit=2');
+ $res = $req->send();
+ $this->assertResponseJson200($res);
+ $data = json_decode($res->getBody());
+ $this->assertInternalType('array', $data);
+ $this->assertEquals(2, count($data));
+ $this->assertContains('foo', $data);
+
+ $req = $this->getRequest('?unittestMode=1&limit=3');
+ $res = $req->send();
+ $this->assertResponseJson200($res);
+ $data = json_decode($res->getBody());
+ $this->assertInternalType('array', $data);
+ $this->assertEquals(3, count($data));
+ $this->assertContains('foo', $data);
+ $this->assertContains('foobar', $data);
+ $this->assertContains('bar', $data);
+ }
+
+}
+
+
+?> \ No newline at end of file
diff --git a/tests/ajax/GetContactTagsTest.php b/tests/ajax/GetContactTagsTest.php
new file mode 100644
index 0000000..559040f
--- /dev/null
+++ b/tests/ajax/GetContactTagsTest.php
@@ -0,0 +1,102 @@
+<?php
+/**
+ * SemanticScuttle - your social bookmark manager.
+ *
+ * PHP version 5.
+ *
+ * @category Bookmarking
+ * @package SemanticScuttle
+ * @author Benjamin Huynh-Kim-Bang <mensonge@users.sourceforge.net>
+ * @author Christian Weiske <cweiske@cweiske.de>
+ * @author Eric Dane <ericdane@users.sourceforge.net>
+ * @license GPL http://www.gnu.org/licenses/gpl.html
+ * @link http://sourceforge.net/projects/semanticscuttle
+ */
+
+require_once dirname(__FILE__) . '/../prepare.php';
+require_once 'HTTP/Request2.php';
+
+/**
+ * Unit tests for the ajax getcontacttags.php script
+ *
+ * @category Bookmarking
+ * @package SemanticScuttle
+ * @author Christian Weiske <cweiske@cweiske.de>
+ * @license GPL http://www.gnu.org/licenses/gpl.html
+ * @link http://sourceforge.net/projects/semanticscuttle
+ */
+class ajax_GetContactTagsTest extends TestBaseApi
+{
+ protected $urlPart = 'ajax/getcontacttags.php';
+
+
+ /**
+ * If no user is logged in, no data are returned
+ */
+ public function testNoUserLoggedIn()
+ {
+ $res = $this->getRequest()->send();
+ $this->assertResponseJson200($res);
+ $data = json_decode($res->getBody());
+ $this->assertInternalType('array', $data);
+ $this->assertEquals(0, count($data));
+ }
+
+
+ public function testUserLoggedInWatchlist()
+ {
+ list($req, $uId) = $this->getLoggedInRequest();
+ $this->addBookmark($uId, null, 0, array('public', 'public2'));
+
+ $user2 = $this->addUser();
+ $this->us->setCurrentUserId($uId);
+ $this->us->setWatchStatus($user2);
+ //uId watches user2 now
+ $this->addBookmark($user2, null, 0, array('user2tag'));
+
+ $res = $req->send();
+ $this->assertResponseJson200($res);
+ $data = json_decode($res->getBody());
+ $this->assertInternalType('array', $data);
+ $this->assertEquals(3, count($data));
+ $this->assertContains('public', $data);
+ $this->assertContains('public2', $data);
+ $this->assertContains('user2tag', $data);
+ }
+
+ public function testParameterBeginsWith()
+ {
+ list($req, $uId) = $this->getLoggedInRequest('?beginsWith=bar');
+ $this->addBookmark($uId, null, 0, array('foobar', 'barmann'));
+
+ $res = $req->send();
+ $this->assertResponseJson200($res);
+ $data = json_decode($res->getBody());
+ $this->assertInternalType('array', $data);
+ $this->assertEquals(1, count($data));
+ $this->assertContains('barmann', $data);
+ }
+
+ public function testParameterLimit()
+ {
+ list($req, $uId) = $this->getLoggedInRequest('?limit=2');
+ $this->addBookmark($uId, null, 0, array('foo', 'bar', 'baz', 'omg'));
+
+ $res = $req->send();
+ $this->assertResponseJson200($res);
+ $data = json_decode($res->getBody());
+ $this->assertInternalType('array', $data);
+ $this->assertEquals(2, count($data));
+
+ $req2 = $this->getRequest('?limit=3');
+ $req2->setCookieJar($req->getCookieJar());
+ $res = $req2->send();
+ $this->assertResponseJson200($res);
+ $data = json_decode($res->getBody());
+ $this->assertInternalType('array', $data);
+ $this->assertEquals(3, count($data));
+ }
+}
+
+
+?> \ No newline at end of file
diff --git a/tests/phpunit.xml b/tests/phpunit.xml
new file mode 100644
index 0000000..734fa95
--- /dev/null
+++ b/tests/phpunit.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<phpunit>
+ <filter>
+ <blacklist>
+ <directory suffix=".php">.</directory>
+ </blacklist>
+ </filter>
+</phpunit> \ No newline at end of file
diff --git a/tests/prepare.php b/tests/prepare.php
index ce9cd1c..6afc284 100644
--- a/tests/prepare.php
+++ b/tests/prepare.php
@@ -19,7 +19,13 @@
$_SERVER['HTTP_HOST'] = 'http://localhost/';
define('UNIT_TEST_MODE', true);
-require_once dirname(__FILE__) . '/../src/SemanticScuttle/header.php';
+if ('@data_dir@' == '@' . 'data_dir@') {
+ //non pear-install
+ require_once dirname(__FILE__) . '/../src/SemanticScuttle/header.php';
+} else {
+ //pear installation; files are in include path
+ require_once 'SemanticScuttle/header.php';
+}
require_once dirname(__FILE__) . '/TestBase.php';
require_once dirname(__FILE__) . '/TestBaseApi.php';
diff --git a/www/ajax/getadminlinkedtags.php b/www/ajax/getadminlinkedtags.php
index 6646c50..5f939a6 100644
--- a/www/ajax/getadminlinkedtags.php
+++ b/www/ajax/getadminlinkedtags.php
@@ -1,64 +1,92 @@
<?php
-/***************************************************************************
- Copyright (C) 2004 - 2006 Scuttle project
- http://sourceforge.net/projects/scuttle/
- http://scuttle.org/
+/**
+ * Returns a list of tags managed by the admins, in json format
+ * suitable for jsTree consumption.
+ *
+ * @param string $tag Tag for which the children tags shall be returned
+ *
+ * SemanticScuttle - your social bookmark manager.
+ *
+ * PHP version 5.
+ *
+ * @category Bookmarking
+ * @package SemanticScuttle
+ * @subcategory Templates
+ * @author Benjamin Huynh-Kim-Bang <mensonge@users.sourceforge.net>
+ * @author Christian Weiske <cweiske@cweiske.de>
+ * @author Eric Dane <ericdane@users.sourceforge.net>
+ * @license GPL http://www.gnu.org/licenses/gpl.html
+ * @link http://sourceforge.net/projects/semanticscuttle
+ */
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- ***************************************************************************/
-
-/* Return a json file with list of linked tags */
$httpContentType = 'application/json';
require_once '../www-header.php';
-/* Service creation: only useful services are created */
-$b2tservice =SemanticScuttle_Service_Factory::get('Bookmark2Tag');
-$bookmarkservice =SemanticScuttle_Service_Factory::get('Tag');
-$tagstatservice =SemanticScuttle_Service_Factory::get('TagStat');
+/**
+ * Creates and returns an array of tags for the jsTree ajax loader.
+ * If the tag is empty, the configured menu2 (admin) main tags are used.
+ *
+ * @param string $tag Tag name to fetch subtags for
+ * @param SemanticScuttle_Service_Tag2Tag $t2t Tag relation service
+ *
+ * @return array Array of tag data suitable for the jsTree ajax loader
+ */
+function assembleAdminTagData($tag, SemanticScuttle_Service_Tag2Tag $t2t)
+{
+ if ($tag == '') {
+ $linkedTags = $GLOBALS['menu2Tags'];
+ } else {
+ $linkedTags = $t2t->getAdminLinkedTags($tag, '>');
+ }
-/* Managing all possible inputs */
-isset($_GET['tag']) ? define('GET_TAG', $_GET['tag']): define('GET_TAG', '');
-isset($_GET['uId']) ? define('GET_UID', $_GET['uId']): define('GET_UID', '');
+ $tagData = array();
+ foreach ($linkedTags as $tag) {
+ //FIXME: the hasChildren code is nasty, because it causes too many
+ // queries onto the database
+ $hasChildren = 0 < count($t2t->getAdminLinkedTags($tag, '>'));
+ $tagData[] = createTagArray($tag, $hasChildren);
+ }
+ return $tagData;
+}
-function displayTag($tag, $uId) {
- $uId = ($uId==0)?NULL:$uId; // if user is nobody, NULL allows to look for every public tags
-
- $tag2tagservice =SemanticScuttle_Service_Factory::get('Tag2Tag');
- $output = '{ id:'.rand().', name:\''.$tag.'\'';
-
- $linkedTags = $tag2tagservice->getAdminLinkedTags($tag, '>');
- if(count($linkedTags) > 0) {
- $output.= ', children: [';
- foreach($linkedTags as $linkedTag) {
- $output.= displayTag($linkedTag, $uId);
- }
- $output = substr($output, 0, -1); // remove final comma avoiding IE6 Dojo bug
- $output.= "]";
- }
+/**
+ * Creates an jsTree json array for the given tag
+ *
+ * @param string $tag Tag name
+ * @param boolean $hasChildren If the tag has subtags (children) or not.
+ * If unsure, set it to "true".
+ *
+ * @return array Array to be sent back to the browser as json
+ */
+function createTagArray($tag, $hasChildren = true)
+{
+ $ar = array(
+ 'data' => array(
+ //<a> attributes
+ 'title' => $tag,
+ 'attr' => array(
+ 'href' => createUrl('tags', $tag)
+ )
+ ),
+ //<li> attributes
+ 'attr' => array(
+ 'rel' => $tag,//needed for identifying the tag in html
+ ),
+ );
+ if ($hasChildren) {
+ //jstree needs that to show the arrows
+ $ar['state'] = 'closed';
+ }
- $output.= '},';
- return $output;
+ return $ar;
}
-?>
-{ label: 'name', identifier: 'id', items: [
-<?php
-$json = displayTag(GET_TAG, intval(GET_UID));
-$json = substr($json, 0, -1); // remove final comma avoiding IE6 Dojo bug
-echo $json;
-?>
-] }
+$tag = isset($_GET['tag']) ? trim($_GET['tag']) : '';
+$tagData = assembleAdminTagData(
+ $tag,
+ SemanticScuttle_Service_Factory::get('Tag2Tag')
+);
+echo json_encode($tagData);
+?> \ No newline at end of file
diff --git a/www/ajax/getadmintags.php b/www/ajax/getadmintags.php
index ffd20bb..2f13060 100644
--- a/www/ajax/getadmintags.php
+++ b/www/ajax/getadmintags.php
@@ -1,44 +1,47 @@
<?php
-/***************************************************************************
-Copyright (C) 2004 - 2006 Scuttle project
-http://sourceforge.net/projects/scuttle/
-http://scuttle.org/
+/**
+ * Return a json file with list of public tags used by admins and sorted
+ * by popularity.
+ *
+ * The following GET parameters are accepted:
+ * @param string $beginsWith The tag name shall start with that string.
+ * No default.
+ * @param integer $limit Number of tags to return. Defaults to 1000
+ *
+ * Part of SemanticScuttle - your social bookmark manager.
+ *
+ * PHP version 5.
+ *
+ * @category Bookmarking
+ * @package SemanticScuttle
+ * @author Benjamin Huynh-Kim-Bang <mensonge@users.sourceforge.net>
+ * @author Christian Weiske <cweiske@cweiske.de>
+ * @author Eric Dane <ericdane@users.sourceforge.net>
+ * @license GPL http://www.gnu.org/licenses/gpl.html
+ * @link http://sourceforge.net/projects/semanticscuttle
+ */
-This program is free software; you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2 of the License, or
-(at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program; if not, write to the Free Software
-Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-***************************************************************************/
-
-/* Return a json file with list of tags according to current user and sort by popularity*/
$httpContentType = 'application/json';
require_once '../www-header.php';
-/* Service creation: only useful services are created */
-$b2tservice =SemanticScuttle_Service_Factory::get('Bookmark2Tag');
-$bookmarkservice =SemanticScuttle_Service_Factory::get('Tag');
-
-?>
-
-{identifier:"tag",
-items: [
-<?php
- $listTags = $b2tservice->getAdminTags(1000, $userservice->getCurrentUserId());
- foreach($listTags as $t) {
- echo "{tag: \"".$t['tag']."\"},";
- }
-?>
-]}
-
-
-
-
+$limit = 30;
+$beginsWith = null;
+$currentUserId = $userservice->getCurrentUserId();
+
+if (isset($_GET['limit']) && is_numeric($_GET['limit'])) {
+ $limit = (int)$_GET['limit'];
+}
+if (isset($_GET['beginsWith']) && strlen(trim($_GET['beginsWith']))) {
+ $beginsWith = trim($_GET['beginsWith']);
+}
+
+$listTags = SemanticScuttle_Service_Factory::get('Bookmark2Tag')->getAdminTags(
+ $limit, $currentUserId, null, $beginsWith
+);
+$tags = array();
+foreach ($listTags as $t) {
+ $tags[] = $t['tag'];
+}
+
+echo json_encode($tags);
+?> \ No newline at end of file
diff --git a/www/ajax/getcontacttags.php b/www/ajax/getcontacttags.php
index 89d6a3a..d353226 100644
--- a/www/ajax/getcontacttags.php
+++ b/www/ajax/getcontacttags.php
@@ -1,44 +1,47 @@
<?php
-/***************************************************************************
-Copyright (C) 2004 - 2006 Scuttle project
-http://sourceforge.net/projects/scuttle/
-http://scuttle.org/
+/**
+ * Return a json file with list of tags according to current user
+ * and sorted by popularity.
+ *
+ * The following GET parameters are accepted:
+ * @param string $beginsWith The tag name shall start with that string.
+ * No default.
+ * @param integer $limit Number of tags to return. Defaults to 1000
+ *
+ * Part of SemanticScuttle - your social bookmark manager.
+ *
+ * PHP version 5.
+ *
+ * @category Bookmarking
+ * @package SemanticScuttle
+ * @author Benjamin Huynh-Kim-Bang <mensonge@users.sourceforge.net>
+ * @author Christian Weiske <cweiske@cweiske.de>
+ * @author Eric Dane <ericdane@users.sourceforge.net>
+ * @license GPL http://www.gnu.org/licenses/gpl.html
+ * @link http://sourceforge.net/projects/semanticscuttle
+ */
-This program is free software; you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2 of the License, or
-(at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program; if not, write to the Free Software
-Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-***************************************************************************/
-
-/* Return a json file with list of tags according to current user and sort by popularity*/
$httpContentType = 'application/json';
require_once '../www-header.php';
-/* Service creation: only useful services are created */
-$b2tservice =SemanticScuttle_Service_Factory::get('Bookmark2Tag');
-$bookmarkservice =SemanticScuttle_Service_Factory::get('Tag');
-
+$limit = 30;
+$beginsWith = null;
+$currentUserId = $userservice->getCurrentUserId();
+
+if (isset($_GET['limit']) && is_numeric($_GET['limit'])) {
+ $limit = (int)$_GET['limit'];
+}
+if (isset($_GET['beginsWith']) && strlen(trim($_GET['beginsWith']))) {
+ $beginsWith = trim($_GET['beginsWith']);
+}
+
+$listTags = SemanticScuttle_Service_Factory::get('Bookmark2Tag')->getContactTags(
+ $currentUserId, $limit, $currentUserId, null, $beginsWith
+);
+$tags = array();
+foreach ($listTags as $t) {
+ $tags[] = $t['tag'];
+}
+
+echo json_encode($tags);
?>
-
-{identifier:"tag",
-items: [
-<?php
- $listTags = $b2tservice->getContactTags($userservice->getCurrentUserId(), 1000, $userservice->getCurrentUserId());
- foreach($listTags as $t) {
- echo "{tag: \"".$t['tag']."\"},";
- }
-?>
-]}
-
-
-
-
diff --git a/www/ajax/getlinkedtags.php b/www/ajax/getlinkedtags.php
index f412998..d8ddb5b 100644
--- a/www/ajax/getlinkedtags.php
+++ b/www/ajax/getlinkedtags.php
@@ -1,64 +1,142 @@
<?php
-/***************************************************************************
- Copyright (C) 2004 - 2006 Scuttle project
- http://sourceforge.net/projects/scuttle/
- http://scuttle.org/
+/**
+ * Returns a list of tags linked to the given one,
+ * suitable for jsTree consumption.
+ *
+ * Accepted GET parameters:
+ *
+ * @param string $tag Tag for which the children tags shall be returned
+ * Multiple tags (separated with space or "+") are
+ * supported.
+ * If no tag is given, all top-level tags are loaded.
+ * @param integer $uId User ID to fetch the tags for
+ * @param boolean $parent Load parent tags
+ *
+ * SemanticScuttle - your social bookmark manager.
+ *
+ * PHP version 5.
+ *
+ * @category Bookmarking
+ * @package SemanticScuttle
+ * @subpackage Templates
+ * @author Benjamin Huynh-Kim-Bang <mensonge@users.sourceforge.net>
+ * @author Christian Weiske <cweiske@cweiske.de>
+ * @author Eric Dane <ericdane@users.sourceforge.net>
+ * @license GPL http://www.gnu.org/licenses/gpl.html
+ * @link http://sourceforge.net/projects/semanticscuttle
+ */
+$httpContentType = 'application/json';
+require_once '../www-header.php';
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
+$tag = isset($_GET['tag']) ? $_GET['tag'] : null;
+$uId = isset($_GET['uId']) ? (int)$_GET['uId'] : 0;
+$loadParentTags = isset($_GET['parent']) ? (bool)$_GET['parent'] : false;
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
+$tags = explode(' ', trim($tag));
+if (count($tags) == 1 && $tags[0] == '') {
+ //no tags
+ $tags = array();
+}
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- ***************************************************************************/
-/* Return a json file with list of linked tags */
-$httpContentType = 'application/json';
-require_once '../www-header.php';
+function assembleLinkedTagData(
+ $tags, $uId, $loadParentTags, SemanticScuttle_Service_Tag2Tag $t2t
+) {
+ $tagData = array();
-/* Service creation: only useful services are created */
-$b2tservice =SemanticScuttle_Service_Factory::get('Bookmark2Tag');
-$bookmarkservice =SemanticScuttle_Service_Factory::get('Tag');
-$tagstatservice =SemanticScuttle_Service_Factory::get('TagStat');
+ if (count($tags) == 0) {
+ //no tags given -> show the 4 most used top-level tags
+ $orphewTags = $t2t->getOrphewTags('>', $uId, 4, 'nb');
+ #$orphewTags = $t2t->getOrphewTags('>', $uId);
+ foreach ($orphewTags as $orphewTag) {
+ $tags[] = $orphewTag['tag'];
+ }
+ $loadParentTags = true;
+ }
-/* Managing all possible inputs */
-isset($_GET['tag']) ? define('GET_TAG', $_GET['tag']): define('GET_TAG', '');
-isset($_GET['uId']) ? define('GET_UID', $_GET['uId']): define('GET_UID', '');
+ if ($loadParentTags) {
+ //find parent tags + append the selected tags as children afterwards
+ foreach ($tags as $tag) {
+ $parentTags = $t2t->getLinkedTags($tag, '>', $uId, true);
+ if (count($parentTags) > 0) {
+ foreach ($parentTags as $parentTag) {
+ $ta = createTagArray(
+ $parentTag, true, true, true
+ );
+ //FIXME: find out if there are subtags
+ $tac = createTagArray($tag, true);
+ $ta['children'][] = $tac;
+ $tagData[] = $ta;
+ }
+ } else {
+ //no parent tags -> display it normally
+ //FIXME: find out if there are subtags
+ $tagData[] = createTagArray($tag, true);
+ }
+ }
+ } else {
+ //just find the linked tags
+ foreach ($tags as $tag) {
+ $linkedTags = $t2t->getLinkedTags($tag, '>', $uId);
+ foreach ($linkedTags as $linkedTag) {
+ //FIXME: find out if there are subtags
+ $tagData[] = createTagArray($linkedTag, true);
+ }
+ }
+ }
+ return $tagData;
+}
-function displayTag($tag, $uId) {
- $uId = ($uId==0)?NULL:$uId; // if user is nobody, NULL allows to look for every public tags
-
- $tag2tagservice =SemanticScuttle_Service_Factory::get('Tag2Tag');
- $output = '{ id:'.rand().', name:\''.$tag.'\'';
+/**
+ * Creates an jsTree json array for the given tag
+ *
+ * @param string $tag Tag name
+ * @param boolean $hasChildren If the tag has subtags (children) or not.
+ * If unsure, set it to "true".
+ * @param boolean $isOpen If the tag has children: Is the tree node open
+ * or closed?
+ * @param boolean $autoParent If the tag is an automatically generated parent tag
+ *
+ * @return array Array to be sent back to the browser as json
+ */
+function createTagArray($tag, $hasChildren = true, $isOpen = false, $autoParent = false)
+{
+ if ($autoParent) {
+ $title = '(' . $tag . ')';
+ } else {
+ $title = $tag;
+ }
- $linkedTags = $tag2tagservice->getLinkedTags($tag, '>', $uId);
- if(count($linkedTags) > 0) {
- $output.= ', children: [';
- foreach($linkedTags as $linkedTag) {
- $output.= displayTag($linkedTag, $uId);
- }
- $output = substr($output, 0, -1); // remove final comma avoiding IE6 Dojo bug
- $output.= "]";
- }
+ $ar = array(
+ 'data' => array(
+ //<a> attributes
+ 'title' => $title,
+ 'attr' => array(
+ 'href' => createUrl('tags', $tag)
+ )
+ ),
+ //<li> attributes
+ 'attr' => array(
+ 'rel' => $tag,//needed for identifying the tag in html
+ ),
+ );
+ if ($hasChildren) {
+ //jstree needs that to show the arrows
+ $ar['state'] = $isOpen ? 'open' : 'closed';
+ }
+ if ($autoParent) {
+ //FIXME: use css class
+ $ar['data']['attr']['style'] = 'color: #AAA';
+ }
- $output.= '},';
- return $output;
+ return $ar;
}
-?>
-{ label: 'name', identifier: 'id', items: [
-<?php
-$json = displayTag(GET_TAG, intval(GET_UID));
-$json = substr($json, 0, -1); // remove final comma avoiding IE6 Dojo bug
-echo $json;
-?>
-] }
+$tagData = assembleLinkedTagData(
+ $tags, 0/*$uId*/, $loadParentTags,
+ SemanticScuttle_Service_Factory::get('Tag2Tag')
+);
+echo json_encode($tagData);
+?> \ No newline at end of file
diff --git a/www/api/export_html.php b/www/api/export_html.php
index c7c8cf4..33401e7 100644
--- a/www/api/export_html.php
+++ b/www/api/export_html.php
@@ -22,6 +22,8 @@
// del.icio.us behavior:
// - doesn't include the filtered tag as an attribute on the root element (we do)
+//this page here is really not valid in any way
+$httpContentType = 'text/html';
// Force HTTP authentication first!
require_once 'httpauth.inc.php';
diff --git a/www/api/httpauth.inc.php b/www/api/httpauth.inc.php
index 0e3a66d..ee5c7f2 100644
--- a/www/api/httpauth.inc.php
+++ b/www/api/httpauth.inc.php
@@ -1,10 +1,29 @@
<?php
+/**
+ * Checks if the user is logged on and sends a HTTP basic auth
+ * request to the browser if not. In that case the script ends.
+ * If username and password are available, the user service's
+ * login method is used to log the user in.
+ *
+ * SemanticScuttle - your social bookmark manager.
+ *
+ * PHP version 5.
+ *
+ * @category Bookmarking
+ * @package SemanticScuttle
+ * @author Benjamin Huynh-Kim-Bang <mensonge@users.sourceforge.net>
+ * @author Christian Weiske <cweiske@cweiske.de>
+ * @author Eric Dane <ericdane@users.sourceforge.net>
+ * @license GPL http://www.gnu.org/licenses/gpl.html
+ * @link http://sourceforge.net/projects/semanticscuttle
+ */
require_once '../www-header.php';
-// Provides HTTP Basic authentication of a user
-// and logs the user in if necessary
-
-function authenticate() {
+/**
+ * Sends HTTP auth headers to the browser
+ */
+function authenticate()
+{
header('WWW-Authenticate: Basic realm="SemanticScuttle API"');
header('HTTP/1.0 401 Unauthorized');
@@ -26,7 +45,9 @@ if (!$userservice->isLoggedOn()) {
if (!isset($_SERVER['PHP_AUTH_USER'])) {
authenticate();
} else {
- $login = $userservice->login($_SERVER['PHP_AUTH_USER'], $_SERVER['PHP_AUTH_PW']);
+ $login = $userservice->login(
+ $_SERVER['PHP_AUTH_USER'], $_SERVER['PHP_AUTH_PW']
+ );
if ($login) {
$currentUser = $userservice->getCurrentObjectUser();
} else {
diff --git a/www/api/posts_add.php b/www/api/posts_add.php
index 59f7dce..7f9dc59 100644
--- a/www/api/posts_add.php
+++ b/www/api/posts_add.php
@@ -1,67 +1,105 @@
<?php
-// Implements the del.icio.us API request to add a new post.
-// http://delicious.com/help/api#posts_add
-
-// del.icio.us behavior:
-// - tags can't have spaces
-// - address and description are mandatory
-
-// Scuttle behavior:
-// - Additional 'status' variable for privacy
-// - No support for 'replace' variable
+/**
+ * API for adding a new bookmark.
+ *
+ * The following POST and GET parameters are accepted:
+ * @param string $url URL of the bookmark (required)
+ * @param string $description Bookmark title (required)
+ * @param string $extended Extended bookmark description (optional)
+ * @param string $tags Space-separated list of tags (optional)
+ * @param string $dt Date and time of bookmark creation (optional)
+ * Must be of format YYYY-MM-DDTHH:II:SSZ
+ * @param integer $status Visibility status (optional):
+ * - 2 or 'private': Bookmark is totally private
+ * - 1 or 'shared': People on the user's watchlist
+ * can see it
+ * - 0 or 'public': Everyone can see the bookmark
+ * @param string $shared "no" or "yes": Switches between private and
+ * public (optional)
+ * @param string $replace "yes" or "no" - replaces a bookmark with the
+ * same URL (optional)
+ *
+ * Notes:
+ * - tags cannot have spaces
+ * - URL and description (title) are mandatory
+ * - delicious "description" is the "title" in SemanticScuttle
+ * - delicious "extended" is the "description" in SemanticScuttle
+ * - "status" is a SemanticScuttle addition to this API method
+ *
+ * SemanticScuttle - your social bookmark manager.
+ *
+ * PHP version 5.
+ *
+ * @category Bookmarking
+ * @package SemanticScuttle
+ * @author Benjamin Huynh-Kim-Bang <mensonge@users.sourceforge.net>
+ * @author Christian Weiske <cweiske@cweiske.de>
+ * @author Eric Dane <ericdane@users.sourceforge.net>
+ * @license GPL http://www.gnu.org/licenses/gpl.html
+ * @link http://sourceforge.net/projects/semanticscuttle
+ * @link http://www.delicious.com/help/api
+ */
// Force HTTP authentication
$httpContentType = 'text/xml';
require_once 'httpauth.inc.php';
-/* Service creation: only useful services are created */
-$bookmarkservice =SemanticScuttle_Service_Factory::get('Bookmark');
+$bs = SemanticScuttle_Service_Factory::get('Bookmark');
// Get all the bookmark's passed-in information
-if (isset($_REQUEST['url']) && (trim($_REQUEST['url']) != ''))
+if (isset($_REQUEST['url']) && (trim($_REQUEST['url']) != '')) {
$url = trim(urldecode($_REQUEST['url']));
-else
- $url = NULL;
+} else {
+ $url = null;
+}
-if (isset($_REQUEST['description']) && (trim($_REQUEST['description']) != ''))
+if (isset($_REQUEST['description']) && (trim($_REQUEST['description']) != '')) {
$description = trim($_REQUEST['description']);
-else
- $description = NULL;
+} else {
+ $description = null;
+}
-if (isset($_REQUEST['extended']) && (trim($_REQUEST['extended']) != ""))
+if (isset($_REQUEST['extended']) && (trim($_REQUEST['extended']) != '')) {
$extended = trim($_REQUEST['extended']);
-else
- $extended = NULL;
+} else {
+ $extended = null;
+}
-if (isset($_REQUEST['tags']) && (trim($_REQUEST['tags']) != '') && (trim($_REQUEST['tags']) != ','))
+if (isset($_REQUEST['tags']) && (trim($_REQUEST['tags']) != '')
+ && (trim($_REQUEST['tags']) != ',')
+) {
$tags = trim($_REQUEST['tags']);
-else
- $tags = NULL;
+} else {
+ $tags = null;
+}
-if (isset($_REQUEST['dt']) && (trim($_REQUEST['dt']) != ''))
+if (isset($_REQUEST['dt']) && (trim($_REQUEST['dt']) != '')) {
$dt = trim($_REQUEST['dt']);
-else
- $dt = NULL;
+} else {
+ $dt = null;
+}
+
+$replace = isset($_REQUEST['replace']) && ($_REQUEST['replace'] == 'yes');
$status = 0;
if (isset($_REQUEST['status'])) {
$status_str = trim($_REQUEST['status']);
if (is_numeric($status_str)) {
$status = intval($status_str);
- if($status < 0 || $status > 2) {
+ if ($status < 0 || $status > 2) {
$status = 0;
}
} else {
switch ($status_str) {
- case 'private':
- $status = 2;
- break;
- case 'shared':
- $status = 1;
- break;
- default:
- $status = 0;
- break;
+ case 'private':
+ $status = 2;
+ break;
+ case 'shared':
+ $status = 1;
+ break;
+ default:
+ $status = 0;
+ break;
}
}
}
@@ -71,17 +109,38 @@ if (isset($_REQUEST['shared']) && (trim($_REQUEST['shared']) == 'no')) {
}
// Error out if there's no address or description
-if (is_null($url) || is_null($description)) {
- $added = false;
+if (is_null($url)) {
+ header('HTTP/1.0 400 Bad Request');
+ $msg = 'URL missing';
+} else if (is_null($description)) {
+ header('HTTP/1.0 400 Bad Request');
+ $msg = 'Description missing';
} else {
-// We're good with info; now insert it!
- if ($bookmarkservice->bookmarkExists($url, $userservice->getCurrentUserId()))
- $added = false;
- else
- $added = $bookmarkservice->addBookmark($url, $description, $extended, '', $status, $tags, null, $dt, true);
+ // We're good with info; now insert it!
+ $exists = $bs->bookmarkExists($url, $userservice->getCurrentUserId());
+ if ($exists) {
+ if (!$replace) {
+ header('HTTP/1.0 409 Conflict');
+ $msg = 'bookmark does already exist';
+ } else {
+ //delete it before we re-add it
+ $bookmark = $bs->getBookmarkByAddress($url, false);
+ $bId = $bookmark['bId'];
+ $bs->deleteBookmark($bId);
+
+ $exists = false;
+ }
+ }
+
+ if (!$exists) {
+ $added = $bs->addBookmark(
+ $url, $description, $extended, '', $status, $tags, null, $dt, true
+ );
+ $msg = 'done';
+ }
}
// Set up the XML file and output the result.
-echo '<?xml version="1.0" standalone="yes" ?'.">\r\n";
-echo '<result code="'. ($added ? 'done' : 'something went wrong') .'" />';
+echo '<?xml version="1.0" standalone="yes" ?' . ">\r\n";
+echo '<result code="' . $msg .'" />';
?> \ No newline at end of file
diff --git a/www/api/posts_delete.php b/www/api/posts_delete.php
index a63cc62..69b2429 100644
--- a/www/api/posts_delete.php
+++ b/www/api/posts_delete.php
@@ -1,33 +1,57 @@
<?php
-// Implements the del.icio.us API request to delete a post.
-
-// del.icio.us behavior:
-// - returns "done" even if the bookmark doesn't exist;
-// - does NOT allow the hash for the url parameter;
-// - doesn't set the Content-Type to text/xml (we do).
+/**
+ * API for deleting a bookmark.
+ * The delicious API is implemented here.
+ *
+ * The delicious API behaves like that:
+ * - does NOT allow the hash for the url parameter
+ * - doesn't set the Content-Type to text/xml
+ * - we do it correctly, too
+ *
+ * SemanticScuttle - your social bookmark manager.
+ *
+ * PHP version 5.
+ *
+ * @category Bookmarking
+ * @package SemanticScuttle
+ * @author Benjamin Huynh-Kim-Bang <mensonge@users.sourceforge.net>
+ * @author Christian Weiske <cweiske@cweiske.de>
+ * @author Eric Dane <ericdane@users.sourceforge.net>
+ * @license GPL http://www.gnu.org/licenses/gpl.html
+ * @link http://sourceforge.net/projects/semanticscuttle
+ * @link http://www.delicious.com/help/api
+ */
// Force HTTP authentication first!
$httpContentType = 'text/xml';
require_once 'httpauth.inc.php';
-/* Service creation: only useful services are created */
-$bookmarkservice =SemanticScuttle_Service_Factory::get('Bookmark');
-
+$bs = SemanticScuttle_Service_Factory::get('Bookmark');
+$uId = $userservice->getCurrentUserId();
-// Note that del.icio.us only errors out if no URL was passed in; there's no error on attempting
-// to delete a bookmark you don't have.
// Error out if there's no address
-if (is_null($_REQUEST['url'])) {
- $deleted = false;
+if (!isset($_REQUEST['url'])
+ || $_REQUEST['url'] == ''
+) {
+ $msg = 'something went wrong';
+} else if (!$bs->bookmarkExists($_REQUEST['url'], $uId)) {
+ //the user does not have such a bookmark
+ header('HTTP/1.0 404 Not Found');
+ $msg = 'item not found';
} else {
- $bookmark = $bookmarkservice->getBookmarkByAddress($_REQUEST['url']);
- $bid = $bookmark['bId'];
- $delete = $bookmarkservice->deleteBookmark($bid);
- $deleted = true;
+ $bookmark = $bs->getBookmarkByAddress($_REQUEST['url'], false);
+ $bId = $bookmark['bId'];
+ $deleted = $bs->deleteBookmark($bId);
+ $msg = 'done';
+ if (!$deleted) {
+ //something really went wrong
+ header('HTTP/1.0 500 Internal Server Error');
+ $msg = 'something really went wrong';
+ }
}
// Set up the XML file and output the result.
-echo '<?xml version="1.0" standalone="yes" ?'.">\r\n";
-echo '<result code="'. ($deleted ? 'done' : 'something went wrong') .'" />';
+echo '<?xml version="1.0" standalone="yes" ?' . ">\r\n";
+echo '<result code="' . $msg . '" />';
?> \ No newline at end of file
diff --git a/www/api/posts_update.php b/www/api/posts_update.php
index 4aeedc3..4b080e2 100644
--- a/www/api/posts_update.php
+++ b/www/api/posts_update.php
@@ -1,24 +1,44 @@
<?php
-// Implements the del.icio.us API request for a user's last update time and date.
-
-// del.icio.us behavior:
-// - doesn't set the Content-Type to text/xml (we do).
+/**
+ * API for retrieving a user's last update time.
+ * That is the time the user changed a bookmark lastly.
+ * The delicious API is implemented here.
+ *
+ * Delicious also returns "the number of new items in
+ * the user's inbox since it was last visited." - we do
+ * that too, so we are as close at the API as possible,
+ * not breaking delicious clients.
+ *
+ * SemanticScuttle - your social bookmark manager.
+ *
+ * PHP version 5.
+ *
+ * @category Bookmarking
+ * @package SemanticScuttle
+ * @author Benjamin Huynh-Kim-Bang <mensonge@users.sourceforge.net>
+ * @author Christian Weiske <cweiske@cweiske.de>
+ * @author Eric Dane <ericdane@users.sourceforge.net>
+ * @license GPL http://www.gnu.org/licenses/gpl.html
+ * @link http://sourceforge.net/projects/semanticscuttle
+ * @link http://www.delicious.com/help/api
+ */
// Force HTTP authentication first!
$httpContentType = 'text/xml';
require_once 'httpauth.inc.php';
-/* Service creation: only useful services are created */
-$bookmarkservice =SemanticScuttle_Service_Factory::get('Bookmark');
-
-
-// Get the posts relevant to the passed-in variables.
-$bookmarks =& $bookmarkservice->getBookmarks(0, 1, $userservice->getCurrentUserId());
+$bs = SemanticScuttle_Service_Factory::get('Bookmark');
+$bookmarks = $bs->getBookmarks(0, 1, $userservice->getCurrentUserId());
// Set up the XML file and output all the tags.
-echo '<?xml version="1.0" standalone="yes" ?'.">\r\n";
-foreach($bookmarks['bookmarks'] as $row) {
- echo '<update time="'. gmdate('Y-m-d\TH:i:s\Z', strtotime($row['bDatetime'])) .'" />';
+echo '<?xml version="1.0" standalone="yes" ?' . ">\r\n";
+//foreach is used in case there are no bookmarks
+foreach ($bookmarks['bookmarks'] as $row) {
+ echo '<update time="'
+ . gmdate('Y-m-d\TH:i:s\Z', strtotime($row['bDatetime']))
+ . '"'
+ . ' inboxnew="0"'
+ . ' />';
}
?> \ No newline at end of file
diff --git a/www/bookmarks.php b/www/bookmarks.php
index 5241481..3b1d50a 100644
--- a/www/bookmarks.php
+++ b/www/bookmarks.php
@@ -41,7 +41,6 @@ isset($_POST['address']) ? define('POST_ADDRESS', $_POST['address']): define('PO
isset($_POST['description']) ? define('POST_DESCRIPTION', $_POST['description']): define('POST_DESCRIPTION', '');
isset($_POST['privateNote']) ? define('POST_PRIVATENOTE', $_POST['privateNote']): define('POST_PRIVATENOTE', '');
isset($_POST['status']) ? define('POST_STATUS', $_POST['status']): define('POST_STATUS', '');
-isset($_POST['tags']) ? define('POST_TAGS', $_POST['tags']): define('POST_TAGS', '');
isset($_POST['referrer']) ? define('POST_REFERRER', $_POST['referrer']): define('POST_REFERRER', '');
isset($_GET['popup']) ? define('GET_POPUP', $_GET['popup']): define('GET_POPUP', '');
@@ -50,6 +49,10 @@ isset($_POST['popup']) ? define('POST_POPUP', $_POST['popup']): define('POST_POP
isset($_GET['page']) ? define('GET_PAGE', $_GET['page']): define('GET_PAGE', 0);
isset($_GET['sort']) ? define('GET_SORT', $_GET['sort']): define('GET_SORT', '');
+if (!isset($_POST['tags'])) {
+ $_POST['tags'] = array();
+}
+//echo '<p>' . var_export($_POST, true) . '</p>';die();
if ((GET_ACTION == "add") && !$userservice->isLoggedOn()) {
@@ -143,7 +146,7 @@ if ($userservice->isLoggedOn() && POST_SUBMITTED != '') {
$description = trim(POST_DESCRIPTION);
$privateNote = trim(POST_PRIVATENOTE);
$status = intval(POST_STATUS);
- $categories = trim(POST_TAGS);
+ $categories = explode(',', $_POST['tags']);
$saved = true;
if ($bookmarkservice->addBookmark($address, $title, $description, $privateNote, $status, $categories)) {
if (POST_POPUP != '') {
@@ -184,10 +187,10 @@ if ($templatename == 'editbookmark.tpl') {
'bAddress' => stripslashes(POST_ADDRESS),
'bDescription' => stripslashes(POST_DESCRIPTION),
'bPrivateNote' => stripslashes(POST_PRIVATENOTE),
- 'tags' => (POST_TAGS ? explode(',', stripslashes(POST_TAGS)) : array()),
+ 'tags' => ($_POST['tags'] ? $_POST['tags'] : array()),
'bStatus' => 0,
);
- $tplVars['tags'] = POST_TAGS;
+ $tplVars['tags'] = $_POST['tags'];
} else {
if(GET_COPYOF != '') { //copy from bookmarks page
$tplVars['row'] = $bookmarkservice->getBookmark(intval(GET_COPYOF), true);
diff --git a/www/gsearch/index.php b/www/gsearch/index.php
index 585536a..70be05e 100644
--- a/www/gsearch/index.php
+++ b/www/gsearch/index.php
@@ -31,7 +31,9 @@ if($GLOBALS['enableGoogleCustomSearch']==false) {
echo '<p><small>';
echo T_('Admin tips: ');
echo T_('To refresh manually Google Custom Search Engine, goes to: ');
- echo '<a href="http://www.google.com/coop/cse/cref?cref='.ROOT.'search/context.php">http://www.google.com/coop/cse/cref</a><br/>';
+ echo '<a href="http://www.google.com/coop/cse/cref?cref='
+ . ROOT . 'gsearch/context.php">http://www.google.com/coop/cse/cref</a>'
+ . '<br/>';
echo T_('If no result appears, check that all the urls are valid in the admin section.');
echo '</small></p>';
diff --git a/www/js/jquery-ui-1.8.11/jquery.ui.autocomplete.js b/www/js/jquery-ui-1.8.11/jquery.ui.autocomplete.js
new file mode 100644
index 0000000..9342483
--- /dev/null
+++ b/www/js/jquery-ui-1.8.11/jquery.ui.autocomplete.js
@@ -0,0 +1,612 @@
+/*
+ * jQuery UI Autocomplete 1.8.11
+ *
+ * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Autocomplete
+ *
+ * Depends:
+ * jquery.ui.core.js
+ * jquery.ui.widget.js
+ * jquery.ui.position.js
+ */
+(function( $, undefined ) {
+
+// used to prevent race conditions with remote data sources
+var requestIndex = 0;
+
+$.widget( "ui.autocomplete", {
+ options: {
+ appendTo: "body",
+ autoFocus: false,
+ delay: 300,
+ minLength: 1,
+ position: {
+ my: "left top",
+ at: "left bottom",
+ collision: "none"
+ },
+ source: null
+ },
+
+ pending: 0,
+
+ _create: function() {
+ var self = this,
+ doc = this.element[ 0 ].ownerDocument,
+ suppressKeyPress;
+
+ this.element
+ .addClass( "ui-autocomplete-input" )
+ .attr( "autocomplete", "off" )
+ // TODO verify these actually work as intended
+ .attr({
+ role: "textbox",
+ "aria-autocomplete": "list",
+ "aria-haspopup": "true"
+ })
+ .bind( "keydown.autocomplete", function( event ) {
+ if ( self.options.disabled || self.element.attr( "readonly" ) ) {
+ return;
+ }
+
+ suppressKeyPress = false;
+ var keyCode = $.ui.keyCode;
+ switch( event.keyCode ) {
+ case keyCode.PAGE_UP:
+ self._move( "previousPage", event );
+ break;
+ case keyCode.PAGE_DOWN:
+ self._move( "nextPage", event );
+ break;
+ case keyCode.UP:
+ self._move( "previous", event );
+ // prevent moving cursor to beginning of text field in some browsers
+ event.preventDefault();
+ break;
+ case keyCode.DOWN:
+ self._move( "next", event );
+ // prevent moving cursor to end of text field in some browsers
+ event.preventDefault();
+ break;
+ case keyCode.ENTER:
+ case keyCode.NUMPAD_ENTER:
+ // when menu is open and has focus
+ if ( self.menu.active ) {
+ // #6055 - Opera still allows the keypress to occur
+ // which causes forms to submit
+ suppressKeyPress = true;
+ event.preventDefault();
+ }
+ //passthrough - ENTER and TAB both select the current element
+ case keyCode.TAB:
+ if ( !self.menu.active ) {
+ return;
+ }
+ self.menu.select( event );
+ break;
+ case keyCode.ESCAPE:
+ self.element.val( self.term );
+ self.close( event );
+ break;
+ default:
+ // keypress is triggered before the input value is changed
+ clearTimeout( self.searching );
+ self.searching = setTimeout(function() {
+ // only search if the value has changed
+ if ( self.term != self.element.val() ) {
+ self.selectedItem = null;
+ self.search( null, event );
+ }
+ }, self.options.delay );
+ break;
+ }
+ })
+ .bind( "keypress.autocomplete", function( event ) {
+ if ( suppressKeyPress ) {
+ suppressKeyPress = false;
+ event.preventDefault();
+ }
+ })
+ .bind( "focus.autocomplete", function() {
+ if ( self.options.disabled ) {
+ return;
+ }
+
+ self.selectedItem = null;
+ self.previous = self.element.val();
+ })
+ .bind( "blur.autocomplete", function( event ) {
+ if ( self.options.disabled ) {
+ return;
+ }
+
+ clearTimeout( self.searching );
+ // clicks on the menu (or a button to trigger a search) will cause a blur event
+ self.closing = setTimeout(function() {
+ self.close( event );
+ self._change( event );
+ }, 150 );
+ });
+ this._initSource();
+ this.response = function() {
+ return self._response.apply( self, arguments );
+ };
+ this.menu = $( "<ul></ul>" )
+ .addClass( "ui-autocomplete" )
+ .appendTo( $( this.options.appendTo || "body", doc )[0] )
+ // prevent the close-on-blur in case of a "slow" click on the menu (long mousedown)
+ .mousedown(function( event ) {
+ // clicking on the scrollbar causes focus to shift to the body
+ // but we can't detect a mouseup or a click immediately afterward
+ // so we have to track the next mousedown and close the menu if
+ // the user clicks somewhere outside of the autocomplete
+ var menuElement = self.menu.element[ 0 ];
+ if ( !$( event.target ).closest( ".ui-menu-item" ).length ) {
+ setTimeout(function() {
+ $( document ).one( 'mousedown', function( event ) {
+ if ( event.target !== self.element[ 0 ] &&
+ event.target !== menuElement &&
+ !$.ui.contains( menuElement, event.target ) ) {
+ self.close();
+ }
+ });
+ }, 1 );
+ }
+
+ // use another timeout to make sure the blur-event-handler on the input was already triggered
+ setTimeout(function() {
+ clearTimeout( self.closing );
+ }, 13);
+ })
+ .menu({
+ focus: function( event, ui ) {
+ var item = ui.item.data( "item.autocomplete" );
+ if ( false !== self._trigger( "focus", event, { item: item } ) ) {
+ // use value to match what will end up in the input, if it was a key event
+ if ( /^key/.test(event.originalEvent.type) ) {
+ self.element.val( item.value );
+ }
+ }
+ },
+ selected: function( event, ui ) {
+ var item = ui.item.data( "item.autocomplete" ),
+ previous = self.previous;
+
+ // only trigger when focus was lost (click on menu)
+ if ( self.element[0] !== doc.activeElement ) {
+ self.element.focus();
+ self.previous = previous;
+ // #6109 - IE triggers two focus events and the second
+ // is asynchronous, so we need to reset the previous
+ // term synchronously and asynchronously :-(
+ setTimeout(function() {
+ self.previous = previous;
+ self.selectedItem = item;
+ }, 1);
+ }
+
+ if ( false !== self._trigger( "select", event, { item: item } ) ) {
+ self.element.val( item.value );
+ }
+ // reset the term after the select event
+ // this allows custom select handling to work properly
+ self.term = self.element.val();
+
+ self.close( event );
+ self.selectedItem = item;
+ },
+ blur: function( event, ui ) {
+ // don't set the value of the text field if it's already correct
+ // this prevents moving the cursor unnecessarily
+ if ( self.menu.element.is(":visible") &&
+ ( self.element.val() !== self.term ) ) {
+ self.element.val( self.term );
+ }
+ }
+ })
+ .zIndex( this.element.zIndex() + 1 )
+ // workaround for jQuery bug #5781 http://dev.jquery.com/ticket/5781
+ .css({ top: 0, left: 0 })
+ .hide()
+ .data( "menu" );
+ if ( $.fn.bgiframe ) {
+ this.menu.element.bgiframe();
+ }
+ },
+
+ destroy: function() {
+ this.element
+ .removeClass( "ui-autocomplete-input" )
+ .removeAttr( "autocomplete" )
+ .removeAttr( "role" )
+ .removeAttr( "aria-autocomplete" )
+ .removeAttr( "aria-haspopup" );
+ this.menu.element.remove();
+ $.Widget.prototype.destroy.call( this );
+ },
+
+ _setOption: function( key, value ) {
+ $.Widget.prototype._setOption.apply( this, arguments );
+ if ( key === "source" ) {
+ this._initSource();
+ }
+ if ( key === "appendTo" ) {
+ this.menu.element.appendTo( $( value || "body", this.element[0].ownerDocument )[0] )
+ }
+ if ( key === "disabled" && value && this.xhr ) {
+ this.xhr.abort();
+ }
+ },
+
+ _initSource: function() {
+ var self = this,
+ array,
+ url;
+ if ( $.isArray(this.options.source) ) {
+ array = this.options.source;
+ this.source = function( request, response ) {
+ response( $.ui.autocomplete.filter(array, request.term) );
+ };
+ } else if ( typeof this.options.source === "string" ) {
+ url = this.options.source;
+ this.source = function( request, response ) {
+ if ( self.xhr ) {
+ self.xhr.abort();
+ }
+ self.xhr = $.ajax({
+ url: url,
+ data: request,
+ dataType: "json",
+ autocompleteRequest: ++requestIndex,
+ success: function( data, status ) {
+ if ( this.autocompleteRequest === requestIndex ) {
+ response( data );
+ }
+ },
+ error: function() {
+ if ( this.autocompleteRequest === requestIndex ) {
+ response( [] );
+ }
+ }
+ });
+ };
+ } else {
+ this.source = this.options.source;
+ }
+ },
+
+ search: function( value, event ) {
+ value = value != null ? value : this.element.val();
+
+ // always save the actual value, not the one passed as an argument
+ this.term = this.element.val();
+
+ if ( value.length < this.options.minLength ) {
+ return this.close( event );
+ }
+
+ clearTimeout( this.closing );
+ if ( this._trigger( "search", event ) === false ) {
+ return;
+ }
+
+ return this._search( value );
+ },
+
+ _search: function( value ) {
+ this.pending++;
+ this.element.addClass( "ui-autocomplete-loading" );
+
+ this.source( { term: value }, this.response );
+ },
+
+ _response: function( content ) {
+ if ( !this.options.disabled && content && content.length ) {
+ content = this._normalize( content );
+ this._suggest( content );
+ this._trigger( "open" );
+ } else {
+ this.close();
+ }
+ this.pending--;
+ if ( !this.pending ) {
+ this.element.removeClass( "ui-autocomplete-loading" );
+ }
+ },
+
+ close: function( event ) {
+ clearTimeout( this.closing );
+ if ( this.menu.element.is(":visible") ) {
+ this.menu.element.hide();
+ this.menu.deactivate();
+ this._trigger( "close", event );
+ }
+ },
+
+ _change: function( event ) {
+ if ( this.previous !== this.element.val() ) {
+ this._trigger( "change", event, { item: this.selectedItem } );
+ }
+ },
+
+ _normalize: function( items ) {
+ // assume all items have the right format when the first item is complete
+ if ( items.length && items[0].label && items[0].value ) {
+ return items;
+ }
+ return $.map( items, function(item) {
+ if ( typeof item === "string" ) {
+ return {
+ label: item,
+ value: item
+ };
+ }
+ return $.extend({
+ label: item.label || item.value,
+ value: item.value || item.label
+ }, item );
+ });
+ },
+
+ _suggest: function( items ) {
+ var ul = this.menu.element
+ .empty()
+ .zIndex( this.element.zIndex() + 1 );
+ this._renderMenu( ul, items );
+ // TODO refresh should check if the active item is still in the dom, removing the need for a manual deactivate
+ this.menu.deactivate();
+ this.menu.refresh();
+
+ // size and position menu
+ ul.show();
+ this._resizeMenu();
+ ul.position( $.extend({
+ of: this.element
+ }, this.options.position ));
+
+ if ( this.options.autoFocus ) {
+ this.menu.next( new $.Event("mouseover") );
+ }
+ },
+
+ _resizeMenu: function() {
+ var ul = this.menu.element;
+ ul.outerWidth( Math.max(
+ ul.width( "" ).outerWidth(),
+ this.element.outerWidth()
+ ) );
+ },
+
+ _renderMenu: function( ul, items ) {
+ var self = this;
+ $.each( items, function( index, item ) {
+ self._renderItem( ul, item );
+ });
+ },
+
+ _renderItem: function( ul, item) {
+ return $( "<li></li>" )
+ .data( "item.autocomplete", item )
+ .append( $( "<a></a>" ).text( item.label ) )
+ .appendTo( ul );
+ },
+
+ _move: function( direction, event ) {
+ if ( !this.menu.element.is(":visible") ) {
+ this.search( null, event );
+ return;
+ }
+ if ( this.menu.first() && /^previous/.test(direction) ||
+ this.menu.last() && /^next/.test(direction) ) {
+ this.element.val( this.term );
+ this.menu.deactivate();
+ return;
+ }
+ this.menu[ direction ]( event );
+ },
+
+ widget: function() {
+ return this.menu.element;
+ }
+});
+
+$.extend( $.ui.autocomplete, {
+ escapeRegex: function( value ) {
+ return value.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&");
+ },
+ filter: function(array, term) {
+ var matcher = new RegExp( $.ui.autocomplete.escapeRegex(term), "i" );
+ return $.grep( array, function(value) {
+ return matcher.test( value.label || value.value || value );
+ });
+ }
+});
+
+}( jQuery ));
+
+/*
+ * jQuery UI Menu (not officially released)
+ *
+ * This widget isn't yet finished and the API is subject to change. We plan to finish
+ * it for the next release. You're welcome to give it a try anyway and give us feedback,
+ * as long as you're okay with migrating your code later on. We can help with that, too.
+ *
+ * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Menu
+ *
+ * Depends:
+ * jquery.ui.core.js
+ * jquery.ui.widget.js
+ */
+(function($) {
+
+$.widget("ui.menu", {
+ _create: function() {
+ var self = this;
+ this.element
+ .addClass("ui-menu ui-widget ui-widget-content ui-corner-all")
+ .attr({
+ role: "listbox",
+ "aria-activedescendant": "ui-active-menuitem"
+ })
+ .click(function( event ) {
+ if ( !$( event.target ).closest( ".ui-menu-item a" ).length ) {
+ return;
+ }
+ // temporary
+ event.preventDefault();
+ self.select( event );
+ });
+ this.refresh();
+ },
+
+ refresh: function() {
+ var self = this;
+
+ // don't refresh list items that are already adapted
+ var items = this.element.children("li:not(.ui-menu-item):has(a)")
+ .addClass("ui-menu-item")
+ .attr("role", "menuitem");
+
+ items.children("a")
+ .addClass("ui-corner-all")
+ .attr("tabindex", -1)
+ // mouseenter doesn't work with event delegation
+ .mouseenter(function( event ) {
+ self.activate( event, $(this).parent() );
+ })
+ .mouseleave(function() {
+ self.deactivate();
+ });
+ },
+
+ activate: function( event, item ) {
+ this.deactivate();
+ if (this.hasScroll()) {
+ var offset = item.offset().top - this.element.offset().top,
+ scroll = this.element.attr("scrollTop"),
+ elementHeight = this.element.height();
+ if (offset < 0) {
+ this.element.attr("scrollTop", scroll + offset);
+ } else if (offset >= elementHeight) {
+ this.element.attr("scrollTop", scroll + offset - elementHeight + item.height());
+ }
+ }
+ this.active = item.eq(0)
+ .children("a")
+ .addClass("ui-state-hover")
+ .attr("id", "ui-active-menuitem")
+ .end();
+ this._trigger("focus", event, { item: item });
+ },
+
+ deactivate: function() {
+ if (!this.active) { return; }
+
+ this.active.children("a")
+ .removeClass("ui-state-hover")
+ .removeAttr("id");
+ this._trigger("blur");
+ this.active = null;
+ },
+
+ next: function(event) {
+ this.move("next", ".ui-menu-item:first", event);
+ },
+
+ previous: function(event) {
+ this.move("prev", ".ui-menu-item:last", event);
+ },
+
+ first: function() {
+ return this.active && !this.active.prevAll(".ui-menu-item").length;
+ },
+
+ last: function() {
+ return this.active && !this.active.nextAll(".ui-menu-item").length;
+ },
+
+ move: function(direction, edge, event) {
+ if (!this.active) {
+ this.activate(event, this.element.children(edge));
+ return;
+ }
+ var next = this.active[direction + "All"](".ui-menu-item").eq(0);
+ if (next.length) {
+ this.activate(event, next);
+ } else {
+ this.activate(event, this.element.children(edge));
+ }
+ },
+
+ // TODO merge with previousPage
+ nextPage: function(event) {
+ if (this.hasScroll()) {
+ // TODO merge with no-scroll-else
+ if (!this.active || this.last()) {
+ this.activate(event, this.element.children(".ui-menu-item:first"));
+ return;
+ }
+ var base = this.active.offset().top,
+ height = this.element.height(),
+ result = this.element.children(".ui-menu-item").filter(function() {
+ var close = $(this).offset().top - base - height + $(this).height();
+ // TODO improve approximation
+ return close < 10 && close > -10;
+ });
+
+ // TODO try to catch this earlier when scrollTop indicates the last page anyway
+ if (!result.length) {
+ result = this.element.children(".ui-menu-item:last");
+ }
+ this.activate(event, result);
+ } else {
+ this.activate(event, this.element.children(".ui-menu-item")
+ .filter(!this.active || this.last() ? ":first" : ":last"));
+ }
+ },
+
+ // TODO merge with nextPage
+ previousPage: function(event) {
+ if (this.hasScroll()) {
+ // TODO merge with no-scroll-else
+ if (!this.active || this.first()) {
+ this.activate(event, this.element.children(".ui-menu-item:last"));
+ return;
+ }
+
+ var base = this.active.offset().top,
+ height = this.element.height();
+ result = this.element.children(".ui-menu-item").filter(function() {
+ var close = $(this).offset().top - base + height - $(this).height();
+ // TODO improve approximation
+ return close < 10 && close > -10;
+ });
+
+ // TODO try to catch this earlier when scrollTop indicates the last page anyway
+ if (!result.length) {
+ result = this.element.children(".ui-menu-item:first");
+ }
+ this.activate(event, result);
+ } else {
+ this.activate(event, this.element.children(".ui-menu-item")
+ .filter(!this.active || this.first() ? ":last" : ":first"));
+ }
+ },
+
+ hasScroll: function() {
+ return this.element.height() < this.element.attr("scrollHeight");
+ },
+
+ select: function( event ) {
+ this._trigger("selected", event, { item: this.active });
+ }
+});
+
+}(jQuery));
diff --git a/www/js/jquery-ui-1.8.11/jquery.ui.autocomplete.min.js b/www/js/jquery-ui-1.8.11/jquery.ui.autocomplete.min.js
new file mode 100644
index 0000000..9331247
--- /dev/null
+++ b/www/js/jquery-ui-1.8.11/jquery.ui.autocomplete.min.js
@@ -0,0 +1,32 @@
+/*
+ * jQuery UI Autocomplete 1.8.11
+ *
+ * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Autocomplete
+ *
+ * Depends:
+ * jquery.ui.core.js
+ * jquery.ui.widget.js
+ * jquery.ui.position.js
+ */
+(function(d){var e=0;d.widget("ui.autocomplete",{options:{appendTo:"body",autoFocus:false,delay:300,minLength:1,position:{my:"left top",at:"left bottom",collision:"none"},source:null},pending:0,_create:function(){var a=this,b=this.element[0].ownerDocument,g;this.element.addClass("ui-autocomplete-input").attr("autocomplete","off").attr({role:"textbox","aria-autocomplete":"list","aria-haspopup":"true"}).bind("keydown.autocomplete",function(c){if(!(a.options.disabled||a.element.attr("readonly"))){g=
+false;var f=d.ui.keyCode;switch(c.keyCode){case f.PAGE_UP:a._move("previousPage",c);break;case f.PAGE_DOWN:a._move("nextPage",c);break;case f.UP:a._move("previous",c);c.preventDefault();break;case f.DOWN:a._move("next",c);c.preventDefault();break;case f.ENTER:case f.NUMPAD_ENTER:if(a.menu.active){g=true;c.preventDefault()}case f.TAB:if(!a.menu.active)return;a.menu.select(c);break;case f.ESCAPE:a.element.val(a.term);a.close(c);break;default:clearTimeout(a.searching);a.searching=setTimeout(function(){if(a.term!=
+a.element.val()){a.selectedItem=null;a.search(null,c)}},a.options.delay);break}}}).bind("keypress.autocomplete",function(c){if(g){g=false;c.preventDefault()}}).bind("focus.autocomplete",function(){if(!a.options.disabled){a.selectedItem=null;a.previous=a.element.val()}}).bind("blur.autocomplete",function(c){if(!a.options.disabled){clearTimeout(a.searching);a.closing=setTimeout(function(){a.close(c);a._change(c)},150)}});this._initSource();this.response=function(){return a._response.apply(a,arguments)};
+this.menu=d("<ul></ul>").addClass("ui-autocomplete").appendTo(d(this.options.appendTo||"body",b)[0]).mousedown(function(c){var f=a.menu.element[0];d(c.target).closest(".ui-menu-item").length||setTimeout(function(){d(document).one("mousedown",function(h){h.target!==a.element[0]&&h.target!==f&&!d.ui.contains(f,h.target)&&a.close()})},1);setTimeout(function(){clearTimeout(a.closing)},13)}).menu({focus:function(c,f){f=f.item.data("item.autocomplete");false!==a._trigger("focus",c,{item:f})&&/^key/.test(c.originalEvent.type)&&
+a.element.val(f.value)},selected:function(c,f){var h=f.item.data("item.autocomplete"),i=a.previous;if(a.element[0]!==b.activeElement){a.element.focus();a.previous=i;setTimeout(function(){a.previous=i;a.selectedItem=h},1)}false!==a._trigger("select",c,{item:h})&&a.element.val(h.value);a.term=a.element.val();a.close(c);a.selectedItem=h},blur:function(){a.menu.element.is(":visible")&&a.element.val()!==a.term&&a.element.val(a.term)}}).zIndex(this.element.zIndex()+1).css({top:0,left:0}).hide().data("menu");
+d.fn.bgiframe&&this.menu.element.bgiframe()},destroy:function(){this.element.removeClass("ui-autocomplete-input").removeAttr("autocomplete").removeAttr("role").removeAttr("aria-autocomplete").removeAttr("aria-haspopup");this.menu.element.remove();d.Widget.prototype.destroy.call(this)},_setOption:function(a,b){d.Widget.prototype._setOption.apply(this,arguments);a==="source"&&this._initSource();if(a==="appendTo")this.menu.element.appendTo(d(b||"body",this.element[0].ownerDocument)[0]);a==="disabled"&&
+b&&this.xhr&&this.xhr.abort()},_initSource:function(){var a=this,b,g;if(d.isArray(this.options.source)){b=this.options.source;this.source=function(c,f){f(d.ui.autocomplete.filter(b,c.term))}}else if(typeof this.options.source==="string"){g=this.options.source;this.source=function(c,f){a.xhr&&a.xhr.abort();a.xhr=d.ajax({url:g,data:c,dataType:"json",autocompleteRequest:++e,success:function(h){this.autocompleteRequest===e&&f(h)},error:function(){this.autocompleteRequest===e&&f([])}})}}else this.source=
+this.options.source},search:function(a,b){a=a!=null?a:this.element.val();this.term=this.element.val();if(a.length<this.options.minLength)return this.close(b);clearTimeout(this.closing);if(this._trigger("search",b)!==false)return this._search(a)},_search:function(a){this.pending++;this.element.addClass("ui-autocomplete-loading");this.source({term:a},this.response)},_response:function(a){if(!this.options.disabled&&a&&a.length){a=this._normalize(a);this._suggest(a);this._trigger("open")}else this.close();
+this.pending--;this.pending||this.element.removeClass("ui-autocomplete-loading")},close:function(a){clearTimeout(this.closing);if(this.menu.element.is(":visible")){this.menu.element.hide();this.menu.deactivate();this._trigger("close",a)}},_change:function(a){this.previous!==this.element.val()&&this._trigger("change",a,{item:this.selectedItem})},_normalize:function(a){if(a.length&&a[0].label&&a[0].value)return a;return d.map(a,function(b){if(typeof b==="string")return{label:b,value:b};return d.extend({label:b.label||
+b.value,value:b.value||b.label},b)})},_suggest:function(a){var b=this.menu.element.empty().zIndex(this.element.zIndex()+1);this._renderMenu(b,a);this.menu.deactivate();this.menu.refresh();b.show();this._resizeMenu();b.position(d.extend({of:this.element},this.options.position));this.options.autoFocus&&this.menu.next(new d.Event("mouseover"))},_resizeMenu:function(){var a=this.menu.element;a.outerWidth(Math.max(a.width("").outerWidth(),this.element.outerWidth()))},_renderMenu:function(a,b){var g=this;
+d.each(b,function(c,f){g._renderItem(a,f)})},_renderItem:function(a,b){return d("<li></li>").data("item.autocomplete",b).append(d("<a></a>").text(b.label)).appendTo(a)},_move:function(a,b){if(this.menu.element.is(":visible"))if(this.menu.first()&&/^previous/.test(a)||this.menu.last()&&/^next/.test(a)){this.element.val(this.term);this.menu.deactivate()}else this.menu[a](b);else this.search(null,b)},widget:function(){return this.menu.element}});d.extend(d.ui.autocomplete,{escapeRegex:function(a){return a.replace(/[-[\]{}()*+?.,\\^$|#\s]/g,
+"\\$&")},filter:function(a,b){var g=new RegExp(d.ui.autocomplete.escapeRegex(b),"i");return d.grep(a,function(c){return g.test(c.label||c.value||c)})}})})(jQuery);
+(function(d){d.widget("ui.menu",{_create:function(){var e=this;this.element.addClass("ui-menu ui-widget ui-widget-content ui-corner-all").attr({role:"listbox","aria-activedescendant":"ui-active-menuitem"}).click(function(a){if(d(a.target).closest(".ui-menu-item a").length){a.preventDefault();e.select(a)}});this.refresh()},refresh:function(){var e=this;this.element.children("li:not(.ui-menu-item):has(a)").addClass("ui-menu-item").attr("role","menuitem").children("a").addClass("ui-corner-all").attr("tabindex",
+-1).mouseenter(function(a){e.activate(a,d(this).parent())}).mouseleave(function(){e.deactivate()})},activate:function(e,a){this.deactivate();if(this.hasScroll()){var b=a.offset().top-this.element.offset().top,g=this.element.attr("scrollTop"),c=this.element.height();if(b<0)this.element.attr("scrollTop",g+b);else b>=c&&this.element.attr("scrollTop",g+b-c+a.height())}this.active=a.eq(0).children("a").addClass("ui-state-hover").attr("id","ui-active-menuitem").end();this._trigger("focus",e,{item:a})},
+deactivate:function(){if(this.active){this.active.children("a").removeClass("ui-state-hover").removeAttr("id");this._trigger("blur");this.active=null}},next:function(e){this.move("next",".ui-menu-item:first",e)},previous:function(e){this.move("prev",".ui-menu-item:last",e)},first:function(){return this.active&&!this.active.prevAll(".ui-menu-item").length},last:function(){return this.active&&!this.active.nextAll(".ui-menu-item").length},move:function(e,a,b){if(this.active){e=this.active[e+"All"](".ui-menu-item").eq(0);
+e.length?this.activate(b,e):this.activate(b,this.element.children(a))}else this.activate(b,this.element.children(a))},nextPage:function(e){if(this.hasScroll())if(!this.active||this.last())this.activate(e,this.element.children(".ui-menu-item:first"));else{var a=this.active.offset().top,b=this.element.height(),g=this.element.children(".ui-menu-item").filter(function(){var c=d(this).offset().top-a-b+d(this).height();return c<10&&c>-10});g.length||(g=this.element.children(".ui-menu-item:last"));this.activate(e,
+g)}else this.activate(e,this.element.children(".ui-menu-item").filter(!this.active||this.last()?":first":":last"))},previousPage:function(e){if(this.hasScroll())if(!this.active||this.first())this.activate(e,this.element.children(".ui-menu-item:last"));else{var a=this.active.offset().top,b=this.element.height();result=this.element.children(".ui-menu-item").filter(function(){var g=d(this).offset().top-a+b-d(this).height();return g<10&&g>-10});result.length||(result=this.element.children(".ui-menu-item:first"));
+this.activate(e,result)}else this.activate(e,this.element.children(".ui-menu-item").filter(!this.active||this.first()?":last":":first"))},hasScroll:function(){return this.element.height()<this.element.attr("scrollHeight")},select:function(e){this._trigger("selected",e,{item:this.active})}})})(jQuery);
diff --git a/www/js/jquery-ui-1.8.11/jquery.ui.core.js b/www/js/jquery-ui-1.8.11/jquery.ui.core.js
new file mode 100644
index 0000000..4589a47
--- /dev/null
+++ b/www/js/jquery-ui-1.8.11/jquery.ui.core.js
@@ -0,0 +1,308 @@
+/*!
+ * jQuery UI 1.8.11
+ *
+ * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI
+ */
+(function( $, undefined ) {
+
+// prevent duplicate loading
+// this is only a problem because we proxy existing functions
+// and we don't want to double proxy them
+$.ui = $.ui || {};
+if ( $.ui.version ) {
+ return;
+}
+
+$.extend( $.ui, {
+ version: "1.8.11",
+
+ keyCode: {
+ ALT: 18,
+ BACKSPACE: 8,
+ CAPS_LOCK: 20,
+ COMMA: 188,
+ COMMAND: 91,
+ COMMAND_LEFT: 91, // COMMAND
+ COMMAND_RIGHT: 93,
+ CONTROL: 17,
+ DELETE: 46,
+ DOWN: 40,
+ END: 35,
+ ENTER: 13,
+ ESCAPE: 27,
+ HOME: 36,
+ INSERT: 45,
+ LEFT: 37,
+ MENU: 93, // COMMAND_RIGHT
+ 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,
+ WINDOWS: 91 // COMMAND
+ }
+});
+
+// plugins
+$.fn.extend({
+ _focus: $.fn.focus,
+ focus: function( delay, fn ) {
+ return typeof delay === "number" ?
+ this.each(function() {
+ var elem = this;
+ setTimeout(function() {
+ $( elem ).focus();
+ if ( fn ) {
+ fn.call( elem );
+ }
+ }, delay );
+ }) :
+ this._focus.apply( this, arguments );
+ },
+
+ 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;
+ },
+
+ zIndex: function( zIndex ) {
+ if ( zIndex !== undefined ) {
+ return this.css( "zIndex", zIndex );
+ }
+
+ if ( this.length ) {
+ var elem = $( this[ 0 ] ), position, value;
+ while ( elem.length && elem[ 0 ] !== document ) {
+ // Ignore z-index if position is set to a value where z-index is ignored by the browser
+ // This makes behavior of this function consistent across browsers
+ // WebKit always returns auto if the element is positioned
+ position = elem.css( "position" );
+ if ( position === "absolute" || position === "relative" || position === "fixed" ) {
+ // IE returns 0 when zIndex is not specified
+ // other browsers return a string
+ // we ignore the case of nested elements with an explicit value of 0
+ // <div style="z-index: -10;"><div style="z-index: 0;"></div></div>
+ value = parseInt( elem.css( "zIndex" ), 10 );
+ if ( !isNaN( value ) && value !== 0 ) {
+ return value;
+ }
+ }
+ elem = elem.parent();
+ }
+ }
+
+ return 0;
+ },
+
+ disableSelection: function() {
+ return this.bind( ( $.support.selectstart ? "selectstart" : "mousedown" ) +
+ ".ui-disableSelection", function( event ) {
+ event.preventDefault();
+ });
+ },
+
+ enableSelection: function() {
+ return this.unbind( ".ui-disableSelection" );
+ }
+});
+
+$.each( [ "Width", "Height" ], function( i, name ) {
+ var side = name === "Width" ? [ "Left", "Right" ] : [ "Top", "Bottom" ],
+ type = name.toLowerCase(),
+ orig = {
+ innerWidth: $.fn.innerWidth,
+ innerHeight: $.fn.innerHeight,
+ outerWidth: $.fn.outerWidth,
+ outerHeight: $.fn.outerHeight
+ };
+
+ function reduce( elem, size, border, margin ) {
+ $.each( side, function() {
+ size -= parseFloat( $.curCSS( elem, "padding" + this, true) ) || 0;
+ if ( border ) {
+ size -= parseFloat( $.curCSS( elem, "border" + this + "Width", true) ) || 0;
+ }
+ if ( margin ) {
+ size -= parseFloat( $.curCSS( elem, "margin" + this, true) ) || 0;
+ }
+ });
+ return size;
+ }
+
+ $.fn[ "inner" + name ] = function( size ) {
+ if ( size === undefined ) {
+ return orig[ "inner" + name ].call( this );
+ }
+
+ return this.each(function() {
+ $( this ).css( type, reduce( this, size ) + "px" );
+ });
+ };
+
+ $.fn[ "outer" + name] = function( size, margin ) {
+ if ( typeof size !== "number" ) {
+ return orig[ "outer" + name ].call( this, size );
+ }
+
+ return this.each(function() {
+ $( this).css( type, reduce( this, size, true, margin ) + "px" );
+ });
+ };
+});
+
+// selectors
+function visible( element ) {
+ return !$( element ).parents().andSelf().filter(function() {
+ return $.curCSS( this, "visibility" ) === "hidden" ||
+ $.expr.filters.hidden( this );
+ }).length;
+}
+
+$.extend( $.expr[ ":" ], {
+ data: function( elem, i, match ) {
+ return !!$.data( elem, match[ 3 ] );
+ },
+
+ focusable: function( element ) {
+ var nodeName = element.nodeName.toLowerCase(),
+ tabIndex = $.attr( element, "tabindex" );
+ if ( "area" === nodeName ) {
+ var map = element.parentNode,
+ mapName = map.name,
+ img;
+ if ( !element.href || !mapName || map.nodeName.toLowerCase() !== "map" ) {
+ return false;
+ }
+ img = $( "img[usemap=#" + mapName + "]" )[0];
+ return !!img && visible( img );
+ }
+ return ( /input|select|textarea|button|object/.test( nodeName )
+ ? !element.disabled
+ : "a" == nodeName
+ ? element.href || !isNaN( tabIndex )
+ : !isNaN( tabIndex ))
+ // the element and all of its ancestors must be visible
+ && visible( element );
+ },
+
+ tabbable: function( element ) {
+ var tabIndex = $.attr( element, "tabindex" );
+ return ( isNaN( tabIndex ) || tabIndex >= 0 ) && $( element ).is( ":focusable" );
+ }
+});
+
+// support
+$(function() {
+ var body = document.body,
+ div = body.appendChild( div = document.createElement( "div" ) );
+
+ $.extend( div.style, {
+ minHeight: "100px",
+ height: "auto",
+ padding: 0,
+ borderWidth: 0
+ });
+
+ $.support.minHeight = div.offsetHeight === 100;
+ $.support.selectstart = "onselectstart" in div;
+
+ // set display to none to avoid a layout bug in IE
+ // http://dev.jquery.com/ticket/4014
+ body.removeChild( div ).style.display = "none";
+});
+
+
+
+
+
+// deprecated
+$.extend( $.ui, {
+ // $.ui.plugin is deprecated. Use the proxy pattern instead.
+ 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; i < set.length; i++ ) {
+ if ( instance.options[ set[ i ][ 0 ] ] ) {
+ set[ i ][ 1 ].apply( instance.element, args );
+ }
+ }
+ }
+ },
+
+ // will be deprecated when we switch to jQuery 1.4 - use jQuery.contains()
+ contains: function( a, b ) {
+ return document.compareDocumentPosition ?
+ a.compareDocumentPosition( b ) & 16 :
+ a !== b && a.contains( b );
+ },
+
+ // only used by resizable
+ hasScroll: function( el, a ) {
+
+ //If overflow is hidden, the element might have extra content, but the user wants to hide it
+ if ( $( el ).css( "overflow" ) === "hidden") {
+ return false;
+ }
+
+ var scroll = ( a && a === "left" ) ? "scrollLeft" : "scrollTop",
+ has = false;
+
+ if ( el[ scroll ] > 0 ) {
+ return true;
+ }
+
+ // TODO: determine which cases actually cause this to happen
+ // if the element doesn't have the scroll set, see if it's possible to
+ // set the scroll
+ el[ scroll ] = 1;
+ has = ( el[ scroll ] > 0 );
+ el[ scroll ] = 0;
+ return has;
+ },
+
+ // these are odd functions, fix the API or move into individual plugins
+ isOverAxis: function( x, reference, size ) {
+ //Determines when x coordinate is over "b" element axis
+ return ( x > reference ) && ( x < ( reference + size ) );
+ },
+ isOver: function( y, x, top, left, height, width ) {
+ //Determines when x, y coordinates is over "b" element
+ return $.ui.isOverAxis( y, top, height ) && $.ui.isOverAxis( x, left, width );
+ }
+});
+
+})( jQuery );
diff --git a/www/js/jquery-ui-1.8.11/jquery.ui.core.min.js b/www/js/jquery-ui-1.8.11/jquery.ui.core.min.js
new file mode 100644
index 0000000..272fe36
--- /dev/null
+++ b/www/js/jquery-ui-1.8.11/jquery.ui.core.min.js
@@ -0,0 +1,17 @@
+/*!
+ * jQuery UI 1.8.11
+ *
+ * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI
+ */
+(function(c,j){function k(a){return!c(a).parents().andSelf().filter(function(){return c.curCSS(this,"visibility")==="hidden"||c.expr.filters.hidden(this)}).length}c.ui=c.ui||{};if(!c.ui.version){c.extend(c.ui,{version:"1.8.11",keyCode:{ALT:18,BACKSPACE:8,CAPS_LOCK:20,COMMA:188,COMMAND:91,COMMAND_LEFT:91,COMMAND_RIGHT:93,CONTROL:17,DELETE:46,DOWN:40,END:35,ENTER:13,ESCAPE:27,HOME:36,INSERT:45,LEFT:37,MENU:93,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,WINDOWS:91}});c.fn.extend({_focus:c.fn.focus,focus:function(a,b){return typeof a==="number"?this.each(function(){var d=this;setTimeout(function(){c(d).focus();b&&b.call(d)},a)}):this._focus.apply(this,arguments)},scrollParent:function(){var a;a=c.browser.msie&&/(static|relative)/.test(this.css("position"))||/absolute/.test(this.css("position"))?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):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"))||!a.length?c(document):a},zIndex:function(a){if(a!==j)return this.css("zIndex",a);if(this.length){a=c(this[0]);for(var b;a.length&&a[0]!==document;){b=a.css("position");
+if(b==="absolute"||b==="relative"||b==="fixed"){b=parseInt(a.css("zIndex"),10);if(!isNaN(b)&&b!==0)return b}a=a.parent()}}return 0},disableSelection:function(){return this.bind((c.support.selectstart?"selectstart":"mousedown")+".ui-disableSelection",function(a){a.preventDefault()})},enableSelection:function(){return this.unbind(".ui-disableSelection")}});c.each(["Width","Height"],function(a,b){function d(f,g,l,m){c.each(e,function(){g-=parseFloat(c.curCSS(f,"padding"+this,true))||0;if(l)g-=parseFloat(c.curCSS(f,
+"border"+this+"Width",true))||0;if(m)g-=parseFloat(c.curCSS(f,"margin"+this,true))||0});return g}var e=b==="Width"?["Left","Right"]:["Top","Bottom"],h=b.toLowerCase(),i={innerWidth:c.fn.innerWidth,innerHeight:c.fn.innerHeight,outerWidth:c.fn.outerWidth,outerHeight:c.fn.outerHeight};c.fn["inner"+b]=function(f){if(f===j)return i["inner"+b].call(this);return this.each(function(){c(this).css(h,d(this,f)+"px")})};c.fn["outer"+b]=function(f,g){if(typeof f!=="number")return i["outer"+b].call(this,f);return this.each(function(){c(this).css(h,
+d(this,f,true,g)+"px")})}});c.extend(c.expr[":"],{data:function(a,b,d){return!!c.data(a,d[3])},focusable:function(a){var b=a.nodeName.toLowerCase(),d=c.attr(a,"tabindex");if("area"===b){b=a.parentNode;d=b.name;if(!a.href||!d||b.nodeName.toLowerCase()!=="map")return false;a=c("img[usemap=#"+d+"]")[0];return!!a&&k(a)}return(/input|select|textarea|button|object/.test(b)?!a.disabled:"a"==b?a.href||!isNaN(d):!isNaN(d))&&k(a)},tabbable:function(a){var b=c.attr(a,"tabindex");return(isNaN(b)||b>=0)&&c(a).is(":focusable")}});
+c(function(){var a=document.body,b=a.appendChild(b=document.createElement("div"));c.extend(b.style,{minHeight:"100px",height:"auto",padding:0,borderWidth:0});c.support.minHeight=b.offsetHeight===100;c.support.selectstart="onselectstart"in b;a.removeChild(b).style.display="none"});c.extend(c.ui,{plugin:{add:function(a,b,d){a=c.ui[a].prototype;for(var e in d){a.plugins[e]=a.plugins[e]||[];a.plugins[e].push([b,d[e]])}},call:function(a,b,d){if((b=a.plugins[b])&&a.element[0].parentNode)for(var e=0;e<b.length;e++)a.options[b[e][0]]&&
+b[e][1].apply(a.element,d)}},contains:function(a,b){return document.compareDocumentPosition?a.compareDocumentPosition(b)&16:a!==b&&a.contains(b)},hasScroll:function(a,b){if(c(a).css("overflow")==="hidden")return false;b=b&&b==="left"?"scrollLeft":"scrollTop";var d=false;if(a[b]>0)return true;a[b]=1;d=a[b]>0;a[b]=0;return d},isOverAxis:function(a,b,d){return a>b&&a<b+d},isOver:function(a,b,d,e,h,i){return c.ui.isOverAxis(a,d,h)&&c.ui.isOverAxis(b,e,i)}})}})(jQuery);
diff --git a/www/js/jquery-ui-1.8.11/jquery.ui.position.js b/www/js/jquery-ui-1.8.11/jquery.ui.position.js
new file mode 100644
index 0000000..b66e59e
--- /dev/null
+++ b/www/js/jquery-ui-1.8.11/jquery.ui.position.js
@@ -0,0 +1,252 @@
+/*
+ * jQuery UI Position 1.8.11
+ *
+ * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Position
+ */
+(function( $, undefined ) {
+
+$.ui = $.ui || {};
+
+var horizontalPositions = /left|center|right/,
+ verticalPositions = /top|center|bottom/,
+ center = "center",
+ _position = $.fn.position,
+ _offset = $.fn.offset;
+
+$.fn.position = function( options ) {
+ if ( !options || !options.of ) {
+ return _position.apply( this, arguments );
+ }
+
+ // make a copy, we don't want to modify arguments
+ options = $.extend( {}, options );
+
+ var target = $( options.of ),
+ targetElem = target[0],
+ collision = ( options.collision || "flip" ).split( " " ),
+ offset = options.offset ? options.offset.split( " " ) : [ 0, 0 ],
+ targetWidth,
+ targetHeight,
+ basePosition;
+
+ if ( targetElem.nodeType === 9 ) {
+ targetWidth = target.width();
+ targetHeight = target.height();
+ basePosition = { top: 0, left: 0 };
+ // TODO: use $.isWindow() in 1.9
+ } else if ( targetElem.setTimeout ) {
+ targetWidth = target.width();
+ targetHeight = target.height();
+ basePosition = { top: target.scrollTop(), left: target.scrollLeft() };
+ } else if ( targetElem.preventDefault ) {
+ // force left top to allow flipping
+ options.at = "left top";
+ targetWidth = targetHeight = 0;
+ basePosition = { top: options.of.pageY, left: options.of.pageX };
+ } else {
+ targetWidth = target.outerWidth();
+ targetHeight = target.outerHeight();
+ basePosition = target.offset();
+ }
+
+ // force my and at to have valid horizontal and veritcal positions
+ // if a value is missing or invalid, it will be converted to center
+ $.each( [ "my", "at" ], function() {
+ var pos = ( options[this] || "" ).split( " " );
+ if ( pos.length === 1) {
+ pos = horizontalPositions.test( pos[0] ) ?
+ pos.concat( [center] ) :
+ verticalPositions.test( pos[0] ) ?
+ [ center ].concat( pos ) :
+ [ center, center ];
+ }
+ pos[ 0 ] = horizontalPositions.test( pos[0] ) ? pos[ 0 ] : center;
+ pos[ 1 ] = verticalPositions.test( pos[1] ) ? pos[ 1 ] : center;
+ options[ this ] = pos;
+ });
+
+ // normalize collision option
+ if ( collision.length === 1 ) {
+ collision[ 1 ] = collision[ 0 ];
+ }
+
+ // normalize offset option
+ offset[ 0 ] = parseInt( offset[0], 10 ) || 0;
+ if ( offset.length === 1 ) {
+ offset[ 1 ] = offset[ 0 ];
+ }
+ offset[ 1 ] = parseInt( offset[1], 10 ) || 0;
+
+ if ( options.at[0] === "right" ) {
+ basePosition.left += targetWidth;
+ } else if ( options.at[0] === center ) {
+ basePosition.left += targetWidth / 2;
+ }
+
+ if ( options.at[1] === "bottom" ) {
+ basePosition.top += targetHeight;
+ } else if ( options.at[1] === center ) {
+ basePosition.top += targetHeight / 2;
+ }
+
+ basePosition.left += offset[ 0 ];
+ basePosition.top += offset[ 1 ];
+
+ return this.each(function() {
+ var elem = $( this ),
+ elemWidth = elem.outerWidth(),
+ elemHeight = elem.outerHeight(),
+ marginLeft = parseInt( $.curCSS( this, "marginLeft", true ) ) || 0,
+ marginTop = parseInt( $.curCSS( this, "marginTop", true ) ) || 0,
+ collisionWidth = elemWidth + marginLeft +
+ ( parseInt( $.curCSS( this, "marginRight", true ) ) || 0 ),
+ collisionHeight = elemHeight + marginTop +
+ ( parseInt( $.curCSS( this, "marginBottom", true ) ) || 0 ),
+ position = $.extend( {}, basePosition ),
+ collisionPosition;
+
+ if ( options.my[0] === "right" ) {
+ position.left -= elemWidth;
+ } else if ( options.my[0] === center ) {
+ position.left -= elemWidth / 2;
+ }
+
+ if ( options.my[1] === "bottom" ) {
+ position.top -= elemHeight;
+ } else if ( options.my[1] === center ) {
+ position.top -= elemHeight / 2;
+ }
+
+ // prevent fractions (see #5280)
+ position.left = Math.round( position.left );
+ position.top = Math.round( position.top );
+
+ collisionPosition = {
+ left: position.left - marginLeft,
+ top: position.top - marginTop
+ };
+
+ $.each( [ "left", "top" ], function( i, dir ) {
+ if ( $.ui.position[ collision[i] ] ) {
+ $.ui.position[ collision[i] ][ dir ]( position, {
+ targetWidth: targetWidth,
+ targetHeight: targetHeight,
+ elemWidth: elemWidth,
+ elemHeight: elemHeight,
+ collisionPosition: collisionPosition,
+ collisionWidth: collisionWidth,
+ collisionHeight: collisionHeight,
+ offset: offset,
+ my: options.my,
+ at: options.at
+ });
+ }
+ });
+
+ if ( $.fn.bgiframe ) {
+ elem.bgiframe();
+ }
+ elem.offset( $.extend( position, { using: options.using } ) );
+ });
+};
+
+$.ui.position = {
+ fit: {
+ left: function( position, data ) {
+ var win = $( window ),
+ over = data.collisionPosition.left + data.collisionWidth - win.width() - win.scrollLeft();
+ position.left = over > 0 ? position.left - over : Math.max( position.left - data.collisionPosition.left, position.left );
+ },
+ top: function( position, data ) {
+ var win = $( window ),
+ over = data.collisionPosition.top + data.collisionHeight - win.height() - win.scrollTop();
+ position.top = over > 0 ? position.top - over : Math.max( position.top - data.collisionPosition.top, position.top );
+ }
+ },
+
+ flip: {
+ left: function( position, data ) {
+ if ( data.at[0] === center ) {
+ return;
+ }
+ var win = $( window ),
+ over = data.collisionPosition.left + data.collisionWidth - win.width() - win.scrollLeft(),
+ myOffset = data.my[ 0 ] === "left" ?
+ -data.elemWidth :
+ data.my[ 0 ] === "right" ?
+ data.elemWidth :
+ 0,
+ atOffset = data.at[ 0 ] === "left" ?
+ data.targetWidth :
+ -data.targetWidth,
+ offset = -2 * data.offset[ 0 ];
+ position.left += data.collisionPosition.left < 0 ?
+ myOffset + atOffset + offset :
+ over > 0 ?
+ myOffset + atOffset + offset :
+ 0;
+ },
+ top: function( position, data ) {
+ if ( data.at[1] === center ) {
+ return;
+ }
+ var win = $( window ),
+ over = data.collisionPosition.top + data.collisionHeight - win.height() - win.scrollTop(),
+ myOffset = data.my[ 1 ] === "top" ?
+ -data.elemHeight :
+ data.my[ 1 ] === "bottom" ?
+ data.elemHeight :
+ 0,
+ atOffset = data.at[ 1 ] === "top" ?
+ data.targetHeight :
+ -data.targetHeight,
+ offset = -2 * data.offset[ 1 ];
+ position.top += data.collisionPosition.top < 0 ?
+ myOffset + atOffset + offset :
+ over > 0 ?
+ myOffset + atOffset + offset :
+ 0;
+ }
+ }
+};
+
+// offset setter from jQuery 1.4
+if ( !$.offset.setOffset ) {
+ $.offset.setOffset = function( elem, options ) {
+ // set position first, in-case top/left are set even on static elem
+ if ( /static/.test( $.curCSS( elem, "position" ) ) ) {
+ elem.style.position = "relative";
+ }
+ var curElem = $( elem ),
+ curOffset = curElem.offset(),
+ curTop = parseInt( $.curCSS( elem, "top", true ), 10 ) || 0,
+ curLeft = parseInt( $.curCSS( elem, "left", true ), 10) || 0,
+ props = {
+ top: (options.top - curOffset.top) + curTop,
+ left: (options.left - curOffset.left) + curLeft
+ };
+
+ if ( 'using' in options ) {
+ options.using.call( elem, props );
+ } else {
+ curElem.css( props );
+ }
+ };
+
+ $.fn.offset = function( options ) {
+ var elem = this[ 0 ];
+ if ( !elem || !elem.ownerDocument ) { return null; }
+ if ( options ) {
+ return this.each(function() {
+ $.offset.setOffset( this, options );
+ });
+ }
+ return _offset.call( this );
+ };
+}
+
+}( jQuery ));
diff --git a/www/js/jquery-ui-1.8.11/jquery.ui.position.min.js b/www/js/jquery-ui-1.8.11/jquery.ui.position.min.js
new file mode 100644
index 0000000..8a5de73
--- /dev/null
+++ b/www/js/jquery-ui-1.8.11/jquery.ui.position.min.js
@@ -0,0 +1,16 @@
+/*
+ * jQuery UI Position 1.8.11
+ *
+ * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Position
+ */
+(function(c){c.ui=c.ui||{};var n=/left|center|right/,o=/top|center|bottom/,t=c.fn.position,u=c.fn.offset;c.fn.position=function(b){if(!b||!b.of)return t.apply(this,arguments);b=c.extend({},b);var a=c(b.of),d=a[0],g=(b.collision||"flip").split(" "),e=b.offset?b.offset.split(" "):[0,0],h,k,j;if(d.nodeType===9){h=a.width();k=a.height();j={top:0,left:0}}else if(d.setTimeout){h=a.width();k=a.height();j={top:a.scrollTop(),left:a.scrollLeft()}}else if(d.preventDefault){b.at="left top";h=k=0;j={top:b.of.pageY,
+left:b.of.pageX}}else{h=a.outerWidth();k=a.outerHeight();j=a.offset()}c.each(["my","at"],function(){var f=(b[this]||"").split(" ");if(f.length===1)f=n.test(f[0])?f.concat(["center"]):o.test(f[0])?["center"].concat(f):["center","center"];f[0]=n.test(f[0])?f[0]:"center";f[1]=o.test(f[1])?f[1]:"center";b[this]=f});if(g.length===1)g[1]=g[0];e[0]=parseInt(e[0],10)||0;if(e.length===1)e[1]=e[0];e[1]=parseInt(e[1],10)||0;if(b.at[0]==="right")j.left+=h;else if(b.at[0]==="center")j.left+=h/2;if(b.at[1]==="bottom")j.top+=
+k;else if(b.at[1]==="center")j.top+=k/2;j.left+=e[0];j.top+=e[1];return this.each(function(){var f=c(this),l=f.outerWidth(),m=f.outerHeight(),p=parseInt(c.curCSS(this,"marginLeft",true))||0,q=parseInt(c.curCSS(this,"marginTop",true))||0,v=l+p+(parseInt(c.curCSS(this,"marginRight",true))||0),w=m+q+(parseInt(c.curCSS(this,"marginBottom",true))||0),i=c.extend({},j),r;if(b.my[0]==="right")i.left-=l;else if(b.my[0]==="center")i.left-=l/2;if(b.my[1]==="bottom")i.top-=m;else if(b.my[1]==="center")i.top-=
+m/2;i.left=Math.round(i.left);i.top=Math.round(i.top);r={left:i.left-p,top:i.top-q};c.each(["left","top"],function(s,x){c.ui.position[g[s]]&&c.ui.position[g[s]][x](i,{targetWidth:h,targetHeight:k,elemWidth:l,elemHeight:m,collisionPosition:r,collisionWidth:v,collisionHeight:w,offset:e,my:b.my,at:b.at})});c.fn.bgiframe&&f.bgiframe();f.offset(c.extend(i,{using:b.using}))})};c.ui.position={fit:{left:function(b,a){var d=c(window);d=a.collisionPosition.left+a.collisionWidth-d.width()-d.scrollLeft();b.left=
+d>0?b.left-d:Math.max(b.left-a.collisionPosition.left,b.left)},top:function(b,a){var d=c(window);d=a.collisionPosition.top+a.collisionHeight-d.height()-d.scrollTop();b.top=d>0?b.top-d:Math.max(b.top-a.collisionPosition.top,b.top)}},flip:{left:function(b,a){if(a.at[0]!=="center"){var d=c(window);d=a.collisionPosition.left+a.collisionWidth-d.width()-d.scrollLeft();var g=a.my[0]==="left"?-a.elemWidth:a.my[0]==="right"?a.elemWidth:0,e=a.at[0]==="left"?a.targetWidth:-a.targetWidth,h=-2*a.offset[0];b.left+=
+a.collisionPosition.left<0?g+e+h:d>0?g+e+h:0}},top:function(b,a){if(a.at[1]!=="center"){var d=c(window);d=a.collisionPosition.top+a.collisionHeight-d.height()-d.scrollTop();var g=a.my[1]==="top"?-a.elemHeight:a.my[1]==="bottom"?a.elemHeight:0,e=a.at[1]==="top"?a.targetHeight:-a.targetHeight,h=-2*a.offset[1];b.top+=a.collisionPosition.top<0?g+e+h:d>0?g+e+h:0}}}};if(!c.offset.setOffset){c.offset.setOffset=function(b,a){if(/static/.test(c.curCSS(b,"position")))b.style.position="relative";var d=c(b),
+g=d.offset(),e=parseInt(c.curCSS(b,"top",true),10)||0,h=parseInt(c.curCSS(b,"left",true),10)||0;g={top:a.top-g.top+e,left:a.left-g.left+h};"using"in a?a.using.call(b,g):d.css(g)};c.fn.offset=function(b){var a=this[0];if(!a||!a.ownerDocument)return null;if(b)return this.each(function(){c.offset.setOffset(this,b)});return u.call(this)}}})(jQuery);
diff --git a/www/js/jquery-ui-1.8.11/jquery.ui.widget.js b/www/js/jquery-ui-1.8.11/jquery.ui.widget.js
new file mode 100644
index 0000000..b6b1bee
--- /dev/null
+++ b/www/js/jquery-ui-1.8.11/jquery.ui.widget.js
@@ -0,0 +1,262 @@
+/*!
+ * jQuery UI Widget 1.8.11
+ *
+ * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Widget
+ */
+(function( $, undefined ) {
+
+// jQuery 1.4+
+if ( $.cleanData ) {
+ var _cleanData = $.cleanData;
+ $.cleanData = function( elems ) {
+ for ( var i = 0, elem; (elem = elems[i]) != null; i++ ) {
+ $( elem ).triggerHandler( "remove" );
+ }
+ _cleanData( elems );
+ };
+} else {
+ var _remove = $.fn.remove;
+ $.fn.remove = function( selector, keepData ) {
+ return this.each(function() {
+ if ( !keepData ) {
+ if ( !selector || $.filter( selector, [ this ] ).length ) {
+ $( "*", this ).add( [ this ] ).each(function() {
+ $( this ).triggerHandler( "remove" );
+ });
+ }
+ }
+ return _remove.call( $(this), selector, keepData );
+ });
+ };
+}
+
+$.widget = function( name, base, prototype ) {
+ var namespace = name.split( "." )[ 0 ],
+ fullName;
+ name = name.split( "." )[ 1 ];
+ fullName = namespace + "-" + name;
+
+ if ( !prototype ) {
+ prototype = base;
+ base = $.Widget;
+ }
+
+ // create selector for plugin
+ $.expr[ ":" ][ fullName ] = function( elem ) {
+ return !!$.data( elem, name );
+ };
+
+ $[ namespace ] = $[ namespace ] || {};
+ $[ namespace ][ name ] = function( options, element ) {
+ // allow instantiation without initializing for simple inheritance
+ if ( arguments.length ) {
+ this._createWidget( options, element );
+ }
+ };
+
+ var basePrototype = new base();
+ // we need to make the options hash a property directly on the new instance
+ // otherwise we'll modify the options hash on the prototype that we're
+ // inheriting from
+// $.each( basePrototype, function( key, val ) {
+// if ( $.isPlainObject(val) ) {
+// basePrototype[ key ] = $.extend( {}, val );
+// }
+// });
+ basePrototype.options = $.extend( true, {}, basePrototype.options );
+ $[ namespace ][ name ].prototype = $.extend( true, basePrototype, {
+ namespace: namespace,
+ widgetName: name,
+ widgetEventPrefix: $[ namespace ][ name ].prototype.widgetEventPrefix || name,
+ widgetBaseClass: fullName
+ }, prototype );
+
+ $.widget.bridge( name, $[ namespace ][ name ] );
+};
+
+$.widget.bridge = function( name, object ) {
+ $.fn[ name ] = function( options ) {
+ var isMethodCall = typeof options === "string",
+ args = Array.prototype.slice.call( arguments, 1 ),
+ returnValue = this;
+
+ // allow multiple hashes to be passed on init
+ options = !isMethodCall && args.length ?
+ $.extend.apply( null, [ true, options ].concat(args) ) :
+ options;
+
+ // prevent calls to internal methods
+ if ( isMethodCall && options.charAt( 0 ) === "_" ) {
+ return returnValue;
+ }
+
+ if ( isMethodCall ) {
+ this.each(function() {
+ var instance = $.data( this, name ),
+ methodValue = instance && $.isFunction( instance[options] ) ?
+ instance[ options ].apply( instance, args ) :
+ instance;
+ // TODO: add this back in 1.9 and use $.error() (see #5972)
+// if ( !instance ) {
+// throw "cannot call methods on " + name + " prior to initialization; " +
+// "attempted to call method '" + options + "'";
+// }
+// if ( !$.isFunction( instance[options] ) ) {
+// throw "no such method '" + options + "' for " + name + " widget instance";
+// }
+// var methodValue = instance[ options ].apply( instance, args );
+ if ( methodValue !== instance && methodValue !== undefined ) {
+ returnValue = methodValue;
+ return false;
+ }
+ });
+ } else {
+ this.each(function() {
+ var instance = $.data( this, name );
+ if ( instance ) {
+ instance.option( options || {} )._init();
+ } else {
+ $.data( this, name, new object( options, this ) );
+ }
+ });
+ }
+
+ return returnValue;
+ };
+};
+
+$.Widget = function( options, element ) {
+ // allow instantiation without initializing for simple inheritance
+ if ( arguments.length ) {
+ this._createWidget( options, element );
+ }
+};
+
+$.Widget.prototype = {
+ widgetName: "widget",
+ widgetEventPrefix: "",
+ options: {
+ disabled: false
+ },
+ _createWidget: function( options, element ) {
+ // $.widget.bridge stores the plugin instance, but we do it anyway
+ // so that it's stored even before the _create function runs
+ $.data( element, this.widgetName, this );
+ this.element = $( element );
+ this.options = $.extend( true, {},
+ this.options,
+ this._getCreateOptions(),
+ options );
+
+ var self = this;
+ this.element.bind( "remove." + this.widgetName, function() {
+ self.destroy();
+ });
+
+ this._create();
+ this._trigger( "create" );
+ this._init();
+ },
+ _getCreateOptions: function() {
+ return $.metadata && $.metadata.get( this.element[0] )[ this.widgetName ];
+ },
+ _create: function() {},
+ _init: function() {},
+
+ destroy: function() {
+ this.element
+ .unbind( "." + this.widgetName )
+ .removeData( this.widgetName );
+ this.widget()
+ .unbind( "." + this.widgetName )
+ .removeAttr( "aria-disabled" )
+ .removeClass(
+ this.widgetBaseClass + "-disabled " +
+ "ui-state-disabled" );
+ },
+
+ widget: function() {
+ return this.element;
+ },
+
+ option: function( key, value ) {
+ var options = key;
+
+ if ( arguments.length === 0 ) {
+ // don't return a reference to the internal hash
+ return $.extend( {}, this.options );
+ }
+
+ if (typeof key === "string" ) {
+ if ( value === undefined ) {
+ return this.options[ key ];
+ }
+ options = {};
+ options[ key ] = value;
+ }
+
+ this._setOptions( options );
+
+ return this;
+ },
+ _setOptions: function( options ) {
+ var self = this;
+ $.each( options, function( key, value ) {
+ self._setOption( key, value );
+ });
+
+ return this;
+ },
+ _setOption: function( key, value ) {
+ this.options[ key ] = value;
+
+ if ( key === "disabled" ) {
+ this.widget()
+ [ value ? "addClass" : "removeClass"](
+ this.widgetBaseClass + "-disabled" + " " +
+ "ui-state-disabled" )
+ .attr( "aria-disabled", value );
+ }
+
+ return this;
+ },
+
+ enable: function() {
+ return this._setOption( "disabled", false );
+ },
+ disable: function() {
+ return this._setOption( "disabled", true );
+ },
+
+ _trigger: function( type, event, data ) {
+ var callback = this.options[ type ];
+
+ event = $.Event( event );
+ event.type = ( type === this.widgetEventPrefix ?
+ type :
+ this.widgetEventPrefix + type ).toLowerCase();
+ data = data || {};
+
+ // copy original event properties over to the new event
+ // this would happen if we could call $.event.fix instead of $.Event
+ // but we don't have a way to force an event to be fixed multiple times
+ 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() );
+ }
+};
+
+})( jQuery );
diff --git a/www/js/jquery-ui-1.8.11/jquery.ui.widget.min.js b/www/js/jquery-ui-1.8.11/jquery.ui.widget.min.js
new file mode 100644
index 0000000..01cb788
--- /dev/null
+++ b/www/js/jquery-ui-1.8.11/jquery.ui.widget.min.js
@@ -0,0 +1,15 @@
+/*!
+ * jQuery UI Widget 1.8.11
+ *
+ * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Widget
+ */
+(function(b,j){if(b.cleanData){var k=b.cleanData;b.cleanData=function(a){for(var c=0,d;(d=a[c])!=null;c++)b(d).triggerHandler("remove");k(a)}}else{var l=b.fn.remove;b.fn.remove=function(a,c){return this.each(function(){if(!c)if(!a||b.filter(a,[this]).length)b("*",this).add([this]).each(function(){b(this).triggerHandler("remove")});return l.call(b(this),a,c)})}}b.widget=function(a,c,d){var e=a.split(".")[0],f;a=a.split(".")[1];f=e+"-"+a;if(!d){d=c;c=b.Widget}b.expr[":"][f]=function(h){return!!b.data(h,
+a)};b[e]=b[e]||{};b[e][a]=function(h,g){arguments.length&&this._createWidget(h,g)};c=new c;c.options=b.extend(true,{},c.options);b[e][a].prototype=b.extend(true,c,{namespace:e,widgetName:a,widgetEventPrefix:b[e][a].prototype.widgetEventPrefix||a,widgetBaseClass:f},d);b.widget.bridge(a,b[e][a])};b.widget.bridge=function(a,c){b.fn[a]=function(d){var e=typeof d==="string",f=Array.prototype.slice.call(arguments,1),h=this;d=!e&&f.length?b.extend.apply(null,[true,d].concat(f)):d;if(e&&d.charAt(0)==="_")return h;
+e?this.each(function(){var g=b.data(this,a),i=g&&b.isFunction(g[d])?g[d].apply(g,f):g;if(i!==g&&i!==j){h=i;return false}}):this.each(function(){var g=b.data(this,a);g?g.option(d||{})._init():b.data(this,a,new c(d,this))});return h}};b.Widget=function(a,c){arguments.length&&this._createWidget(a,c)};b.Widget.prototype={widgetName:"widget",widgetEventPrefix:"",options:{disabled:false},_createWidget:function(a,c){b.data(c,this.widgetName,this);this.element=b(c);this.options=b.extend(true,{},this.options,
+this._getCreateOptions(),a);var d=this;this.element.bind("remove."+this.widgetName,function(){d.destroy()});this._create();this._trigger("create");this._init()},_getCreateOptions:function(){return b.metadata&&b.metadata.get(this.element[0])[this.widgetName]},_create:function(){},_init:function(){},destroy:function(){this.element.unbind("."+this.widgetName).removeData(this.widgetName);this.widget().unbind("."+this.widgetName).removeAttr("aria-disabled").removeClass(this.widgetBaseClass+"-disabled ui-state-disabled")},
+widget:function(){return this.element},option:function(a,c){var d=a;if(arguments.length===0)return b.extend({},this.options);if(typeof a==="string"){if(c===j)return this.options[a];d={};d[a]=c}this._setOptions(d);return this},_setOptions:function(a){var c=this;b.each(a,function(d,e){c._setOption(d,e)});return this},_setOption:function(a,c){this.options[a]=c;if(a==="disabled")this.widget()[c?"addClass":"removeClass"](this.widgetBaseClass+"-disabled ui-state-disabled").attr("aria-disabled",c);return this},
+enable:function(){return this._setOption("disabled",false)},disable:function(){return this._setOption("disabled",true)},_trigger:function(a,c,d){var e=this.options[a];c=b.Event(c);c.type=(a===this.widgetEventPrefix?a:this.widgetEventPrefix+a).toLowerCase();d=d||{};if(c.originalEvent){a=b.event.props.length;for(var f;a;){f=b.event.props[--a];c[f]=c.originalEvent[f]}}this.element.trigger(c,d);return!(b.isFunction(e)&&e.call(this.element[0],c,d)===false||c.isDefaultPrevented())}}})(jQuery);
diff --git a/www/js/jquery-ui-1.8.11/themes/base/images/ui-bg_flat_0_aaaaaa_40x100.png b/www/js/jquery-ui-1.8.11/themes/base/images/ui-bg_flat_0_aaaaaa_40x100.png
new file mode 100644
index 0000000..5b5dab2
--- /dev/null
+++ b/www/js/jquery-ui-1.8.11/themes/base/images/ui-bg_flat_0_aaaaaa_40x100.png
Binary files differ
diff --git a/www/js/jquery-ui-1.8.11/themes/base/images/ui-bg_flat_75_ffffff_40x100.png b/www/js/jquery-ui-1.8.11/themes/base/images/ui-bg_flat_75_ffffff_40x100.png
new file mode 100644
index 0000000..ac8b229
--- /dev/null
+++ b/www/js/jquery-ui-1.8.11/themes/base/images/ui-bg_flat_75_ffffff_40x100.png
Binary files differ
diff --git a/www/js/jquery-ui-1.8.11/themes/base/images/ui-bg_glass_55_fbf9ee_1x400.png b/www/js/jquery-ui-1.8.11/themes/base/images/ui-bg_glass_55_fbf9ee_1x400.png
new file mode 100644
index 0000000..ad3d634
--- /dev/null
+++ b/www/js/jquery-ui-1.8.11/themes/base/images/ui-bg_glass_55_fbf9ee_1x400.png
Binary files differ
diff --git a/www/js/jquery-ui-1.8.11/themes/base/images/ui-bg_glass_65_ffffff_1x400.png b/www/js/jquery-ui-1.8.11/themes/base/images/ui-bg_glass_65_ffffff_1x400.png
new file mode 100644
index 0000000..42ccba2
--- /dev/null
+++ b/www/js/jquery-ui-1.8.11/themes/base/images/ui-bg_glass_65_ffffff_1x400.png
Binary files differ
diff --git a/www/js/jquery-ui-1.8.11/themes/base/images/ui-bg_glass_75_dadada_1x400.png b/www/js/jquery-ui-1.8.11/themes/base/images/ui-bg_glass_75_dadada_1x400.png
new file mode 100644
index 0000000..5a46b47
--- /dev/null
+++ b/www/js/jquery-ui-1.8.11/themes/base/images/ui-bg_glass_75_dadada_1x400.png
Binary files differ
diff --git a/www/js/jquery-ui-1.8.11/themes/base/images/ui-bg_glass_75_e6e6e6_1x400.png b/www/js/jquery-ui-1.8.11/themes/base/images/ui-bg_glass_75_e6e6e6_1x400.png
new file mode 100644
index 0000000..86c2baa
--- /dev/null
+++ b/www/js/jquery-ui-1.8.11/themes/base/images/ui-bg_glass_75_e6e6e6_1x400.png
Binary files differ
diff --git a/www/js/jquery-ui-1.8.11/themes/base/images/ui-bg_glass_95_fef1ec_1x400.png b/www/js/jquery-ui-1.8.11/themes/base/images/ui-bg_glass_95_fef1ec_1x400.png
new file mode 100644
index 0000000..4443fdc
--- /dev/null
+++ b/www/js/jquery-ui-1.8.11/themes/base/images/ui-bg_glass_95_fef1ec_1x400.png
Binary files differ
diff --git a/www/js/jquery-ui-1.8.11/themes/base/images/ui-bg_highlight-soft_75_cccccc_1x100.png b/www/js/jquery-ui-1.8.11/themes/base/images/ui-bg_highlight-soft_75_cccccc_1x100.png
new file mode 100644
index 0000000..7c9fa6c
--- /dev/null
+++ b/www/js/jquery-ui-1.8.11/themes/base/images/ui-bg_highlight-soft_75_cccccc_1x100.png
Binary files differ
diff --git a/www/js/jquery-ui-1.8.11/themes/base/images/ui-icons_222222_256x240.png b/www/js/jquery-ui-1.8.11/themes/base/images/ui-icons_222222_256x240.png
new file mode 100644
index 0000000..ee039dc
--- /dev/null
+++ b/www/js/jquery-ui-1.8.11/themes/base/images/ui-icons_222222_256x240.png
Binary files differ
diff --git a/www/js/jquery-ui-1.8.11/themes/base/images/ui-icons_2e83ff_256x240.png b/www/js/jquery-ui-1.8.11/themes/base/images/ui-icons_2e83ff_256x240.png
new file mode 100644
index 0000000..45e8928
--- /dev/null
+++ b/www/js/jquery-ui-1.8.11/themes/base/images/ui-icons_2e83ff_256x240.png
Binary files differ
diff --git a/www/js/jquery-ui-1.8.11/themes/base/images/ui-icons_454545_256x240.png b/www/js/jquery-ui-1.8.11/themes/base/images/ui-icons_454545_256x240.png
new file mode 100644
index 0000000..7ec70d1
--- /dev/null
+++ b/www/js/jquery-ui-1.8.11/themes/base/images/ui-icons_454545_256x240.png
Binary files differ
diff --git a/www/js/jquery-ui-1.8.11/themes/base/images/ui-icons_888888_256x240.png b/www/js/jquery-ui-1.8.11/themes/base/images/ui-icons_888888_256x240.png
new file mode 100644
index 0000000..5ba708c
--- /dev/null
+++ b/www/js/jquery-ui-1.8.11/themes/base/images/ui-icons_888888_256x240.png
Binary files differ
diff --git a/www/js/jquery-ui-1.8.11/themes/base/images/ui-icons_cd0a0a_256x240.png b/www/js/jquery-ui-1.8.11/themes/base/images/ui-icons_cd0a0a_256x240.png
new file mode 100644
index 0000000..7930a55
--- /dev/null
+++ b/www/js/jquery-ui-1.8.11/themes/base/images/ui-icons_cd0a0a_256x240.png
Binary files differ
diff --git a/www/js/jquery-ui-1.8.11/themes/base/jquery.ui.all.css b/www/js/jquery-ui-1.8.11/themes/base/jquery.ui.all.css
new file mode 100644
index 0000000..0302dfb
--- /dev/null
+++ b/www/js/jquery-ui-1.8.11/themes/base/jquery.ui.all.css
@@ -0,0 +1,11 @@
+/*
+ * jQuery UI CSS Framework @VERSION
+ *
+ * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Theming
+ */
+@import "jquery.ui.base.css";
+@import "jquery.ui.theme.css";
diff --git a/www/js/jquery-ui-1.8.11/themes/base/jquery.ui.autocomplete.css b/www/js/jquery-ui-1.8.11/themes/base/jquery.ui.autocomplete.css
new file mode 100644
index 0000000..83b7b9d
--- /dev/null
+++ b/www/js/jquery-ui-1.8.11/themes/base/jquery.ui.autocomplete.css
@@ -0,0 +1,53 @@
+/*
+ * jQuery UI Autocomplete 1.8.11
+ *
+ * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Autocomplete#theming
+ */
+.ui-autocomplete { position: absolute; cursor: default; }
+
+/* workarounds */
+* html .ui-autocomplete { width:1px; } /* without this, the menu expands to 100% in IE6 */
+
+/*
+ * jQuery UI Menu 1.8.11
+ *
+ * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Menu#theming
+ */
+.ui-menu {
+ list-style:none;
+ padding: 2px;
+ margin: 0;
+ display:block;
+ float: left;
+}
+.ui-menu .ui-menu {
+ margin-top: -3px;
+}
+.ui-menu .ui-menu-item {
+ margin:0;
+ padding: 0;
+ zoom: 1;
+ float: left;
+ clear: left;
+ width: 100%;
+}
+.ui-menu .ui-menu-item a {
+ text-decoration:none;
+ display:block;
+ padding:.2em .4em;
+ line-height:1.5;
+ zoom:1;
+}
+.ui-menu .ui-menu-item a.ui-state-hover,
+.ui-menu .ui-menu-item a.ui-state-active {
+ font-weight: normal;
+ margin: -1px;
+}
diff --git a/www/js/jquery-ui-1.8.11/themes/base/jquery.ui.base.css b/www/js/jquery-ui-1.8.11/themes/base/jquery.ui.base.css
new file mode 100644
index 0000000..98267a4
--- /dev/null
+++ b/www/js/jquery-ui-1.8.11/themes/base/jquery.ui.base.css
@@ -0,0 +1,2 @@
+@import url("jquery.ui.core.css");
+@import url("jquery.ui.autocomplete.css");
diff --git a/www/js/jquery-ui-1.8.11/themes/base/jquery.ui.core.css b/www/js/jquery-ui-1.8.11/themes/base/jquery.ui.core.css
new file mode 100644
index 0000000..ef27f47
--- /dev/null
+++ b/www/js/jquery-ui-1.8.11/themes/base/jquery.ui.core.css
@@ -0,0 +1,41 @@
+/*
+ * jQuery UI CSS Framework 1.8.11
+ *
+ * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Theming/API
+ */
+
+/* Layout helpers
+----------------------------------*/
+.ui-helper-hidden { display: none; }
+.ui-helper-hidden-accessible { position: absolute !important; clip: rect(1px 1px 1px 1px); clip: rect(1px,1px,1px,1px); }
+.ui-helper-reset { margin: 0; padding: 0; border: 0; outline: 0; line-height: 1.3; text-decoration: none; font-size: 100%; list-style: none; }
+.ui-helper-clearfix:after { content: "."; display: block; height: 0; clear: both; visibility: hidden; }
+.ui-helper-clearfix { display: inline-block; }
+/* required comment for clearfix to work in Opera \*/
+* html .ui-helper-clearfix { height:1%; }
+.ui-helper-clearfix { display:block; }
+/* end clearfix */
+.ui-helper-zfix { width: 100%; height: 100%; top: 0; left: 0; position: absolute; opacity: 0; filter:Alpha(Opacity=0); }
+
+
+/* Interaction Cues
+----------------------------------*/
+.ui-state-disabled { cursor: default !important; }
+
+
+/* Icons
+----------------------------------*/
+
+/* states and images */
+.ui-icon { display: block; text-indent: -99999px; overflow: hidden; background-repeat: no-repeat; }
+
+
+/* Misc visuals
+----------------------------------*/
+
+/* Overlays */
+.ui-widget-overlay { position: absolute; top: 0; left: 0; width: 100%; height: 100%; }
diff --git a/www/js/jquery-ui-1.8.11/themes/base/jquery.ui.theme.css b/www/js/jquery-ui-1.8.11/themes/base/jquery.ui.theme.css
new file mode 100644
index 0000000..30690c5
--- /dev/null
+++ b/www/js/jquery-ui-1.8.11/themes/base/jquery.ui.theme.css
@@ -0,0 +1,252 @@
+/*
+ * jQuery UI CSS Framework 1.8.11
+ *
+ * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Theming/API
+ *
+ * To view and modify this theme, visit http://jqueryui.com/themeroller/
+ */
+
+
+/* Component containers
+----------------------------------*/
+.ui-widget { font-family: Verdana,Arial,sans-serif/*{ffDefault}*/; font-size: 1.1em/*{fsDefault}*/; }
+.ui-widget .ui-widget { font-size: 1em; }
+.ui-widget input, .ui-widget select, .ui-widget textarea, .ui-widget button { font-family: Verdana,Arial,sans-serif/*{ffDefault}*/; font-size: 1em; }
+.ui-widget-content { border: 1px solid #aaaaaa/*{borderColorContent}*/; background: #ffffff/*{bgColorContent}*/ url(images/ui-bg_flat_75_ffffff_40x100.png)/*{bgImgUrlContent}*/ 50%/*{bgContentXPos}*/ 50%/*{bgContentYPos}*/ repeat-x/*{bgContentRepeat}*/; color: #222222/*{fcContent}*/; }
+.ui-widget-content a { color: #222222/*{fcContent}*/; }
+.ui-widget-header { border: 1px solid #aaaaaa/*{borderColorHeader}*/; background: #cccccc/*{bgColorHeader}*/ url(images/ui-bg_highlight-soft_75_cccccc_1x100.png)/*{bgImgUrlHeader}*/ 50%/*{bgHeaderXPos}*/ 50%/*{bgHeaderYPos}*/ repeat-x/*{bgHeaderRepeat}*/; color: #222222/*{fcHeader}*/; font-weight: bold; }
+.ui-widget-header a { color: #222222/*{fcHeader}*/; }
+
+/* Interaction states
+----------------------------------*/
+.ui-state-default, .ui-widget-content .ui-state-default, .ui-widget-header .ui-state-default { border: 1px solid #d3d3d3/*{borderColorDefault}*/; background: #e6e6e6/*{bgColorDefault}*/ url(images/ui-bg_glass_75_e6e6e6_1x400.png)/*{bgImgUrlDefault}*/ 50%/*{bgDefaultXPos}*/ 50%/*{bgDefaultYPos}*/ repeat-x/*{bgDefaultRepeat}*/; font-weight: normal/*{fwDefault}*/; color: #555555/*{fcDefault}*/; }
+.ui-state-default a, .ui-state-default a:link, .ui-state-default a:visited { color: #555555/*{fcDefault}*/; text-decoration: none; }
+.ui-state-hover, .ui-widget-content .ui-state-hover, .ui-widget-header .ui-state-hover, .ui-state-focus, .ui-widget-content .ui-state-focus, .ui-widget-header .ui-state-focus { border: 1px solid #999999/*{borderColorHover}*/; background: #dadada/*{bgColorHover}*/ url(images/ui-bg_glass_75_dadada_1x400.png)/*{bgImgUrlHover}*/ 50%/*{bgHoverXPos}*/ 50%/*{bgHoverYPos}*/ repeat-x/*{bgHoverRepeat}*/; font-weight: normal/*{fwDefault}*/; color: #212121/*{fcHover}*/; }
+.ui-state-hover a, .ui-state-hover a:hover { color: #212121/*{fcHover}*/; text-decoration: none; }
+.ui-state-active, .ui-widget-content .ui-state-active, .ui-widget-header .ui-state-active { border: 1px solid #aaaaaa/*{borderColorActive}*/; background: #ffffff/*{bgColorActive}*/ url(images/ui-bg_glass_65_ffffff_1x400.png)/*{bgImgUrlActive}*/ 50%/*{bgActiveXPos}*/ 50%/*{bgActiveYPos}*/ repeat-x/*{bgActiveRepeat}*/; font-weight: normal/*{fwDefault}*/; color: #212121/*{fcActive}*/; }
+.ui-state-active a, .ui-state-active a:link, .ui-state-active a:visited { color: #212121/*{fcActive}*/; text-decoration: none; }
+.ui-widget :active { outline: none; }
+
+/* Interaction Cues
+----------------------------------*/
+.ui-state-highlight, .ui-widget-content .ui-state-highlight, .ui-widget-header .ui-state-highlight {border: 1px solid #fcefa1/*{borderColorHighlight}*/; background: #fbf9ee/*{bgColorHighlight}*/ url(images/ui-bg_glass_55_fbf9ee_1x400.png)/*{bgImgUrlHighlight}*/ 50%/*{bgHighlightXPos}*/ 50%/*{bgHighlightYPos}*/ repeat-x/*{bgHighlightRepeat}*/; color: #363636/*{fcHighlight}*/; }
+.ui-state-highlight a, .ui-widget-content .ui-state-highlight a,.ui-widget-header .ui-state-highlight a { color: #363636/*{fcHighlight}*/; }
+.ui-state-error, .ui-widget-content .ui-state-error, .ui-widget-header .ui-state-error {border: 1px solid #cd0a0a/*{borderColorError}*/; background: #fef1ec/*{bgColorError}*/ url(images/ui-bg_glass_95_fef1ec_1x400.png)/*{bgImgUrlError}*/ 50%/*{bgErrorXPos}*/ 50%/*{bgErrorYPos}*/ repeat-x/*{bgErrorRepeat}*/; color: #cd0a0a/*{fcError}*/; }
+.ui-state-error a, .ui-widget-content .ui-state-error a, .ui-widget-header .ui-state-error a { color: #cd0a0a/*{fcError}*/; }
+.ui-state-error-text, .ui-widget-content .ui-state-error-text, .ui-widget-header .ui-state-error-text { color: #cd0a0a/*{fcError}*/; }
+.ui-priority-primary, .ui-widget-content .ui-priority-primary, .ui-widget-header .ui-priority-primary { font-weight: bold; }
+.ui-priority-secondary, .ui-widget-content .ui-priority-secondary, .ui-widget-header .ui-priority-secondary { opacity: .7; filter:Alpha(Opacity=70); font-weight: normal; }
+.ui-state-disabled, .ui-widget-content .ui-state-disabled, .ui-widget-header .ui-state-disabled { opacity: .35; filter:Alpha(Opacity=35); background-image: none; }
+
+/* Icons
+----------------------------------*/
+
+/* states and images */
+.ui-icon { width: 16px; height: 16px; background-image: url(images/ui-icons_222222_256x240.png)/*{iconsContent}*/; }
+.ui-widget-content .ui-icon {background-image: url(images/ui-icons_222222_256x240.png)/*{iconsContent}*/; }
+.ui-widget-header .ui-icon {background-image: url(images/ui-icons_222222_256x240.png)/*{iconsHeader}*/; }
+.ui-state-default .ui-icon { background-image: url(images/ui-icons_888888_256x240.png)/*{iconsDefault}*/; }
+.ui-state-hover .ui-icon, .ui-state-focus .ui-icon {background-image: url(images/ui-icons_454545_256x240.png)/*{iconsHover}*/; }
+.ui-state-active .ui-icon {background-image: url(images/ui-icons_454545_256x240.png)/*{iconsActive}*/; }
+.ui-state-highlight .ui-icon {background-image: url(images/ui-icons_2e83ff_256x240.png)/*{iconsHighlight}*/; }
+.ui-state-error .ui-icon, .ui-state-error-text .ui-icon {background-image: url(images/ui-icons_cd0a0a_256x240.png)/*{iconsError}*/; }
+
+/* positioning */
+.ui-icon-carat-1-n { background-position: 0 0; }
+.ui-icon-carat-1-ne { background-position: -16px 0; }
+.ui-icon-carat-1-e { background-position: -32px 0; }
+.ui-icon-carat-1-se { background-position: -48px 0; }
+.ui-icon-carat-1-s { background-position: -64px 0; }
+.ui-icon-carat-1-sw { background-position: -80px 0; }
+.ui-icon-carat-1-w { background-position: -96px 0; }
+.ui-icon-carat-1-nw { background-position: -112px 0; }
+.ui-icon-carat-2-n-s { background-position: -128px 0; }
+.ui-icon-carat-2-e-w { background-position: -144px 0; }
+.ui-icon-triangle-1-n { background-position: 0 -16px; }
+.ui-icon-triangle-1-ne { background-position: -16px -16px; }
+.ui-icon-triangle-1-e { background-position: -32px -16px; }
+.ui-icon-triangle-1-se { background-position: -48px -16px; }
+.ui-icon-triangle-1-s { background-position: -64px -16px; }
+.ui-icon-triangle-1-sw { background-position: -80px -16px; }
+.ui-icon-triangle-1-w { background-position: -96px -16px; }
+.ui-icon-triangle-1-nw { background-position: -112px -16px; }
+.ui-icon-triangle-2-n-s { background-position: -128px -16px; }
+.ui-icon-triangle-2-e-w { background-position: -144px -16px; }
+.ui-icon-arrow-1-n { background-position: 0 -32px; }
+.ui-icon-arrow-1-ne { background-position: -16px -32px; }
+.ui-icon-arrow-1-e { background-position: -32px -32px; }
+.ui-icon-arrow-1-se { background-position: -48px -32px; }
+.ui-icon-arrow-1-s { background-position: -64px -32px; }
+.ui-icon-arrow-1-sw { background-position: -80px -32px; }
+.ui-icon-arrow-1-w { background-position: -96px -32px; }
+.ui-icon-arrow-1-nw { background-position: -112px -32px; }
+.ui-icon-arrow-2-n-s { background-position: -128px -32px; }
+.ui-icon-arrow-2-ne-sw { background-position: -144px -32px; }
+.ui-icon-arrow-2-e-w { background-position: -160px -32px; }
+.ui-icon-arrow-2-se-nw { background-position: -176px -32px; }
+.ui-icon-arrowstop-1-n { background-position: -192px -32px; }
+.ui-icon-arrowstop-1-e { background-position: -208px -32px; }
+.ui-icon-arrowstop-1-s { background-position: -224px -32px; }
+.ui-icon-arrowstop-1-w { background-position: -240px -32px; }
+.ui-icon-arrowthick-1-n { background-position: 0 -48px; }
+.ui-icon-arrowthick-1-ne { background-position: -16px -48px; }
+.ui-icon-arrowthick-1-e { background-position: -32px -48px; }
+.ui-icon-arrowthick-1-se { background-position: -48px -48px; }
+.ui-icon-arrowthick-1-s { background-position: -64px -48px; }
+.ui-icon-arrowthick-1-sw { background-position: -80px -48px; }
+.ui-icon-arrowthick-1-w { background-position: -96px -48px; }
+.ui-icon-arrowthick-1-nw { background-position: -112px -48px; }
+.ui-icon-arrowthick-2-n-s { background-position: -128px -48px; }
+.ui-icon-arrowthick-2-ne-sw { background-position: -144px -48px; }
+.ui-icon-arrowthick-2-e-w { background-position: -160px -48px; }
+.ui-icon-arrowthick-2-se-nw { background-position: -176px -48px; }
+.ui-icon-arrowthickstop-1-n { background-position: -192px -48px; }
+.ui-icon-arrowthickstop-1-e { background-position: -208px -48px; }
+.ui-icon-arrowthickstop-1-s { background-position: -224px -48px; }
+.ui-icon-arrowthickstop-1-w { background-position: -240px -48px; }
+.ui-icon-arrowreturnthick-1-w { background-position: 0 -64px; }
+.ui-icon-arrowreturnthick-1-n { background-position: -16px -64px; }
+.ui-icon-arrowreturnthick-1-e { background-position: -32px -64px; }
+.ui-icon-arrowreturnthick-1-s { background-position: -48px -64px; }
+.ui-icon-arrowreturn-1-w { background-position: -64px -64px; }
+.ui-icon-arrowreturn-1-n { background-position: -80px -64px; }
+.ui-icon-arrowreturn-1-e { background-position: -96px -64px; }
+.ui-icon-arrowreturn-1-s { background-position: -112px -64px; }
+.ui-icon-arrowrefresh-1-w { background-position: -128px -64px; }
+.ui-icon-arrowrefresh-1-n { background-position: -144px -64px; }
+.ui-icon-arrowrefresh-1-e { background-position: -160px -64px; }
+.ui-icon-arrowrefresh-1-s { background-position: -176px -64px; }
+.ui-icon-arrow-4 { background-position: 0 -80px; }
+.ui-icon-arrow-4-diag { background-position: -16px -80px; }
+.ui-icon-extlink { background-position: -32px -80px; }
+.ui-icon-newwin { background-position: -48px -80px; }
+.ui-icon-refresh { background-position: -64px -80px; }
+.ui-icon-shuffle { background-position: -80px -80px; }
+.ui-icon-transfer-e-w { background-position: -96px -80px; }
+.ui-icon-transferthick-e-w { background-position: -112px -80px; }
+.ui-icon-folder-collapsed { background-position: 0 -96px; }
+.ui-icon-folder-open { background-position: -16px -96px; }
+.ui-icon-document { background-position: -32px -96px; }
+.ui-icon-document-b { background-position: -48px -96px; }
+.ui-icon-note { background-position: -64px -96px; }
+.ui-icon-mail-closed { background-position: -80px -96px; }
+.ui-icon-mail-open { background-position: -96px -96px; }
+.ui-icon-suitcase { background-position: -112px -96px; }
+.ui-icon-comment { background-position: -128px -96px; }
+.ui-icon-person { background-position: -144px -96px; }
+.ui-icon-print { background-position: -160px -96px; }
+.ui-icon-trash { background-position: -176px -96px; }
+.ui-icon-locked { background-position: -192px -96px; }
+.ui-icon-unlocked { background-position: -208px -96px; }
+.ui-icon-bookmark { background-position: -224px -96px; }
+.ui-icon-tag { background-position: -240px -96px; }
+.ui-icon-home { background-position: 0 -112px; }
+.ui-icon-flag { background-position: -16px -112px; }
+.ui-icon-calendar { background-position: -32px -112px; }
+.ui-icon-cart { background-position: -48px -112px; }
+.ui-icon-pencil { background-position: -64px -112px; }
+.ui-icon-clock { background-position: -80px -112px; }
+.ui-icon-disk { background-position: -96px -112px; }
+.ui-icon-calculator { background-position: -112px -112px; }
+.ui-icon-zoomin { background-position: -128px -112px; }
+.ui-icon-zoomout { background-position: -144px -112px; }
+.ui-icon-search { background-position: -160px -112px; }
+.ui-icon-wrench { background-position: -176px -112px; }
+.ui-icon-gear { background-position: -192px -112px; }
+.ui-icon-heart { background-position: -208px -112px; }
+.ui-icon-star { background-position: -224px -112px; }
+.ui-icon-link { background-position: -240px -112px; }
+.ui-icon-cancel { background-position: 0 -128px; }
+.ui-icon-plus { background-position: -16px -128px; }
+.ui-icon-plusthick { background-position: -32px -128px; }
+.ui-icon-minus { background-position: -48px -128px; }
+.ui-icon-minusthick { background-position: -64px -128px; }
+.ui-icon-close { background-position: -80px -128px; }
+.ui-icon-closethick { background-position: -96px -128px; }
+.ui-icon-key { background-position: -112px -128px; }
+.ui-icon-lightbulb { background-position: -128px -128px; }
+.ui-icon-scissors { background-position: -144px -128px; }
+.ui-icon-clipboard { background-position: -160px -128px; }
+.ui-icon-copy { background-position: -176px -128px; }
+.ui-icon-contact { background-position: -192px -128px; }
+.ui-icon-image { background-position: -208px -128px; }
+.ui-icon-video { background-position: -224px -128px; }
+.ui-icon-script { background-position: -240px -128px; }
+.ui-icon-alert { background-position: 0 -144px; }
+.ui-icon-info { background-position: -16px -144px; }
+.ui-icon-notice { background-position: -32px -144px; }
+.ui-icon-help { background-position: -48px -144px; }
+.ui-icon-check { background-position: -64px -144px; }
+.ui-icon-bullet { background-position: -80px -144px; }
+.ui-icon-radio-off { background-position: -96px -144px; }
+.ui-icon-radio-on { background-position: -112px -144px; }
+.ui-icon-pin-w { background-position: -128px -144px; }
+.ui-icon-pin-s { background-position: -144px -144px; }
+.ui-icon-play { background-position: 0 -160px; }
+.ui-icon-pause { background-position: -16px -160px; }
+.ui-icon-seek-next { background-position: -32px -160px; }
+.ui-icon-seek-prev { background-position: -48px -160px; }
+.ui-icon-seek-end { background-position: -64px -160px; }
+.ui-icon-seek-start { background-position: -80px -160px; }
+/* ui-icon-seek-first is deprecated, use ui-icon-seek-start instead */
+.ui-icon-seek-first { background-position: -80px -160px; }
+.ui-icon-stop { background-position: -96px -160px; }
+.ui-icon-eject { background-position: -112px -160px; }
+.ui-icon-volume-off { background-position: -128px -160px; }
+.ui-icon-volume-on { background-position: -144px -160px; }
+.ui-icon-power { background-position: 0 -176px; }
+.ui-icon-signal-diag { background-position: -16px -176px; }
+.ui-icon-signal { background-position: -32px -176px; }
+.ui-icon-battery-0 { background-position: -48px -176px; }
+.ui-icon-battery-1 { background-position: -64px -176px; }
+.ui-icon-battery-2 { background-position: -80px -176px; }
+.ui-icon-battery-3 { background-position: -96px -176px; }
+.ui-icon-circle-plus { background-position: 0 -192px; }
+.ui-icon-circle-minus { background-position: -16px -192px; }
+.ui-icon-circle-close { background-position: -32px -192px; }
+.ui-icon-circle-triangle-e { background-position: -48px -192px; }
+.ui-icon-circle-triangle-s { background-position: -64px -192px; }
+.ui-icon-circle-triangle-w { background-position: -80px -192px; }
+.ui-icon-circle-triangle-n { background-position: -96px -192px; }
+.ui-icon-circle-arrow-e { background-position: -112px -192px; }
+.ui-icon-circle-arrow-s { background-position: -128px -192px; }
+.ui-icon-circle-arrow-w { background-position: -144px -192px; }
+.ui-icon-circle-arrow-n { background-position: -160px -192px; }
+.ui-icon-circle-zoomin { background-position: -176px -192px; }
+.ui-icon-circle-zoomout { background-position: -192px -192px; }
+.ui-icon-circle-check { background-position: -208px -192px; }
+.ui-icon-circlesmall-plus { background-position: 0 -208px; }
+.ui-icon-circlesmall-minus { background-position: -16px -208px; }
+.ui-icon-circlesmall-close { background-position: -32px -208px; }
+.ui-icon-squaresmall-plus { background-position: -48px -208px; }
+.ui-icon-squaresmall-minus { background-position: -64px -208px; }
+.ui-icon-squaresmall-close { background-position: -80px -208px; }
+.ui-icon-grip-dotted-vertical { background-position: 0 -224px; }
+.ui-icon-grip-dotted-horizontal { background-position: -16px -224px; }
+.ui-icon-grip-solid-vertical { background-position: -32px -224px; }
+.ui-icon-grip-solid-horizontal { background-position: -48px -224px; }
+.ui-icon-gripsmall-diagonal-se { background-position: -64px -224px; }
+.ui-icon-grip-diagonal-se { background-position: -80px -224px; }
+
+
+/* Misc visuals
+----------------------------------*/
+
+/* Corner radius */
+.ui-corner-tl { -moz-border-radius-topleft: 4px/*{cornerRadius}*/; -webkit-border-top-left-radius: 4px/*{cornerRadius}*/; border-top-left-radius: 4px/*{cornerRadius}*/; }
+.ui-corner-tr { -moz-border-radius-topright: 4px/*{cornerRadius}*/; -webkit-border-top-right-radius: 4px/*{cornerRadius}*/; border-top-right-radius: 4px/*{cornerRadius}*/; }
+.ui-corner-bl { -moz-border-radius-bottomleft: 4px/*{cornerRadius}*/; -webkit-border-bottom-left-radius: 4px/*{cornerRadius}*/; border-bottom-left-radius: 4px/*{cornerRadius}*/; }
+.ui-corner-br { -moz-border-radius-bottomright: 4px/*{cornerRadius}*/; -webkit-border-bottom-right-radius: 4px/*{cornerRadius}*/; border-bottom-right-radius: 4px/*{cornerRadius}*/; }
+.ui-corner-top { -moz-border-radius-topleft: 4px/*{cornerRadius}*/; -webkit-border-top-left-radius: 4px/*{cornerRadius}*/; border-top-left-radius: 4px/*{cornerRadius}*/; -moz-border-radius-topright: 4px/*{cornerRadius}*/; -webkit-border-top-right-radius: 4px/*{cornerRadius}*/; border-top-right-radius: 4px/*{cornerRadius}*/; }
+.ui-corner-bottom { -moz-border-radius-bottomleft: 4px/*{cornerRadius}*/; -webkit-border-bottom-left-radius: 4px/*{cornerRadius}*/; border-bottom-left-radius: 4px/*{cornerRadius}*/; -moz-border-radius-bottomright: 4px/*{cornerRadius}*/; -webkit-border-bottom-right-radius: 4px/*{cornerRadius}*/; border-bottom-right-radius: 4px/*{cornerRadius}*/; }
+.ui-corner-right { -moz-border-radius-topright: 4px/*{cornerRadius}*/; -webkit-border-top-right-radius: 4px/*{cornerRadius}*/; border-top-right-radius: 4px/*{cornerRadius}*/; -moz-border-radius-bottomright: 4px/*{cornerRadius}*/; -webkit-border-bottom-right-radius: 4px/*{cornerRadius}*/; border-bottom-right-radius: 4px/*{cornerRadius}*/; }
+.ui-corner-left { -moz-border-radius-topleft: 4px/*{cornerRadius}*/; -webkit-border-top-left-radius: 4px/*{cornerRadius}*/; border-top-left-radius: 4px/*{cornerRadius}*/; -moz-border-radius-bottomleft: 4px/*{cornerRadius}*/; -webkit-border-bottom-left-radius: 4px/*{cornerRadius}*/; border-bottom-left-radius: 4px/*{cornerRadius}*/; }
+.ui-corner-all { -moz-border-radius: 4px/*{cornerRadius}*/; -webkit-border-radius: 4px/*{cornerRadius}*/; border-radius: 4px/*{cornerRadius}*/; }
+
+/* Overlays */
+.ui-widget-overlay { background: #aaaaaa/*{bgColorOverlay}*/ url(images/ui-bg_flat_0_aaaaaa_40x100.png)/*{bgImgUrlOverlay}*/ 50%/*{bgOverlayXPos}*/ 50%/*{bgOverlayYPos}*/ repeat-x/*{bgOverlayRepeat}*/; opacity: .3;filter:Alpha(Opacity=30)/*{opacityOverlay}*/; }
+.ui-widget-shadow { margin: -8px/*{offsetTopShadow}*/ 0 0 -8px/*{offsetLeftShadow}*/; padding: 8px/*{thicknessShadow}*/; background: #aaaaaa/*{bgColorShadow}*/ url(images/ui-bg_flat_0_aaaaaa_40x100.png)/*{bgImgUrlShadow}*/ 50%/*{bgShadowXPos}*/ 50%/*{bgShadowYPos}*/ repeat-x/*{bgShadowRepeat}*/; opacity: .3;filter:Alpha(Opacity=30)/*{opacityShadow}*/; -moz-border-radius: 8px/*{cornerRadiusShadow}*/; -webkit-border-radius: 8px/*{cornerRadiusShadow}*/; border-radius: 8px/*{cornerRadiusShadow}*/; } \ No newline at end of file
diff --git a/www/js/MultiComboBox.js b/www/js/jstree-1.0-rc2/MultiComboBox.js
index b263c8b..b263c8b 100644
--- a/www/js/MultiComboBox.js
+++ b/www/js/jstree-1.0-rc2/MultiComboBox.js
diff --git a/www/js/jstree-1.0-rc2/jquery-1.4.2.js b/www/js/jstree-1.0-rc2/jquery-1.4.2.js
new file mode 100644
index 0000000..fff6776
--- /dev/null
+++ b/www/js/jstree-1.0-rc2/jquery-1.4.2.js
@@ -0,0 +1,6240 @@
+/*!
+ * jQuery JavaScript Library v1.4.2
+ * http://jquery.com/
+ *
+ * Copyright 2010, John Resig
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * Includes Sizzle.js
+ * http://sizzlejs.com/
+ * Copyright 2010, The Dojo Foundation
+ * Released under the MIT, BSD, and GPL Licenses.
+ *
+ * Date: Sat Feb 13 22:33:48 2010 -0500
+ */
+(function( window, undefined ) {
+
+// Define a local copy of jQuery
+var jQuery = function( selector, context ) {
+ // The jQuery object is actually just the init constructor 'enhanced'
+ return new jQuery.fn.init( selector, context );
+ },
+
+ // Map over jQuery in case of overwrite
+ _jQuery = window.jQuery,
+
+ // Map over the $ in case of overwrite
+ _$ = window.$,
+
+ // Use the correct document accordingly with window argument (sandbox)
+ document = window.document,
+
+ // A central reference to the root jQuery(document)
+ rootjQuery,
+
+ // A simple way to check for HTML strings or ID strings
+ // (both of which we optimize for)
+ quickExpr = /^[^<]*(<[\w\W]+>)[^>]*$|^#([\w-]+)$/,
+
+ // Is it a simple selector
+ isSimple = /^.[^:#\[\.,]*$/,
+
+ // Check if a string has a non-whitespace character in it
+ rnotwhite = /\S/,
+
+ // Used for trimming whitespace
+ rtrim = /^(\s|\u00A0)+|(\s|\u00A0)+$/g,
+
+ // Match a standalone tag
+ rsingleTag = /^<(\w+)\s*\/?>(?:<\/\1>)?$/,
+
+ // Keep a UserAgent string for use with jQuery.browser
+ userAgent = navigator.userAgent,
+
+ // For matching the engine and version of the browser
+ browserMatch,
+
+ // Has the ready events already been bound?
+ readyBound = false,
+
+ // The functions to execute on DOM ready
+ readyList = [],
+
+ // The ready event handler
+ DOMContentLoaded,
+
+ // Save a reference to some core methods
+ toString = Object.prototype.toString,
+ hasOwnProperty = Object.prototype.hasOwnProperty,
+ push = Array.prototype.push,
+ slice = Array.prototype.slice,
+ indexOf = Array.prototype.indexOf;
+
+jQuery.fn = jQuery.prototype = {
+ init: function( selector, context ) {
+ var match, elem, ret, doc;
+
+ // Handle $(""), $(null), or $(undefined)
+ if ( !selector ) {
+ return this;
+ }
+
+ // Handle $(DOMElement)
+ if ( selector.nodeType ) {
+ this.context = this[0] = selector;
+ this.length = 1;
+ return this;
+ }
+
+ // The body element only exists once, optimize finding it
+ if ( selector === "body" && !context ) {
+ this.context = document;
+ this[0] = document.body;
+ this.selector = "body";
+ this.length = 1;
+ return this;
+ }
+
+ // Handle HTML strings
+ if ( typeof selector === "string" ) {
+ // Are we dealing with HTML string or an ID?
+ match = quickExpr.exec( selector );
+
+ // Verify a match, and that no context was specified for #id
+ if ( match && (match[1] || !context) ) {
+
+ // HANDLE: $(html) -> $(array)
+ if ( match[1] ) {
+ doc = (context ? context.ownerDocument || context : document);
+
+ // If a single string is passed in and it's a single tag
+ // just do a createElement and skip the rest
+ ret = rsingleTag.exec( selector );
+
+ if ( ret ) {
+ if ( jQuery.isPlainObject( context ) ) {
+ selector = [ document.createElement( ret[1] ) ];
+ jQuery.fn.attr.call( selector, context, true );
+
+ } else {
+ selector = [ doc.createElement( ret[1] ) ];
+ }
+
+ } else {
+ ret = buildFragment( [ match[1] ], [ doc ] );
+ selector = (ret.cacheable ? ret.fragment.cloneNode(true) : ret.fragment).childNodes;
+ }
+
+ return jQuery.merge( this, selector );
+
+ // HANDLE: $("#id")
+ } else {
+ elem = document.getElementById( match[2] );
+
+ if ( elem ) {
+ // Handle the case where IE and Opera return items
+ // by name instead of ID
+ if ( elem.id !== match[2] ) {
+ return rootjQuery.find( selector );
+ }
+
+ // Otherwise, we inject the element directly into the jQuery object
+ this.length = 1;
+ this[0] = elem;
+ }
+
+ this.context = document;
+ this.selector = selector;
+ return this;
+ }
+
+ // HANDLE: $("TAG")
+ } else if ( !context && /^\w+$/.test( selector ) ) {
+ this.selector = selector;
+ this.context = document;
+ selector = document.getElementsByTagName( selector );
+ return jQuery.merge( this, selector );
+
+ // HANDLE: $(expr, $(...))
+ } else if ( !context || context.jquery ) {
+ return (context || rootjQuery).find( selector );
+
+ // HANDLE: $(expr, context)
+ // (which is just equivalent to: $(context).find(expr)
+ } else {
+ return jQuery( context ).find( selector );
+ }
+
+ // HANDLE: $(function)
+ // Shortcut for document ready
+ } else if ( jQuery.isFunction( selector ) ) {
+ return rootjQuery.ready( selector );
+ }
+
+ if (selector.selector !== undefined) {
+ this.selector = selector.selector;
+ this.context = selector.context;
+ }
+
+ return jQuery.makeArray( selector, this );
+ },
+
+ // Start with an empty selector
+ selector: "",
+
+ // The current version of jQuery being used
+ jquery: "1.4.2",
+
+ // The default length of a jQuery object is 0
+ length: 0,
+
+ // The number of elements contained in the matched element set
+ size: function() {
+ return this.length;
+ },
+
+ toArray: function() {
+ return slice.call( this, 0 );
+ },
+
+ // Get the Nth element in the matched element set OR
+ // Get the whole matched element set as a clean array
+ get: function( num ) {
+ return num == null ?
+
+ // Return a 'clean' array
+ this.toArray() :
+
+ // Return just the object
+ ( num < 0 ? this.slice(num)[ 0 ] : this[ num ] );
+ },
+
+ // Take an array of elements and push it onto the stack
+ // (returning the new matched element set)
+ pushStack: function( elems, name, selector ) {
+ // Build a new jQuery matched element set
+ var ret = jQuery();
+
+ if ( jQuery.isArray( elems ) ) {
+ push.apply( ret, elems );
+
+ } else {
+ jQuery.merge( ret, elems );
+ }
+
+ // Add the old object onto the stack (as a reference)
+ ret.prevObject = this;
+
+ ret.context = this.context;
+
+ if ( name === "find" ) {
+ ret.selector = this.selector + (this.selector ? " " : "") + selector;
+ } else if ( name ) {
+ ret.selector = this.selector + "." + name + "(" + selector + ")";
+ }
+
+ // Return the newly-formed element set
+ return ret;
+ },
+
+ // Execute a callback for every element in the matched set.
+ // (You can seed the arguments with an array of args, but this is
+ // only used internally.)
+ each: function( callback, args ) {
+ return jQuery.each( this, callback, args );
+ },
+
+ ready: function( fn ) {
+ // Attach the listeners
+ jQuery.bindReady();
+
+ // If the DOM is already ready
+ if ( jQuery.isReady ) {
+ // Execute the function immediately
+ fn.call( document, jQuery );
+
+ // Otherwise, remember the function for later
+ } else if ( readyList ) {
+ // Add the function to the wait list
+ readyList.push( fn );
+ }
+
+ return this;
+ },
+
+ eq: function( i ) {
+ return i === -1 ?
+ this.slice( i ) :
+ this.slice( i, +i + 1 );
+ },
+
+ first: function() {
+ return this.eq( 0 );
+ },
+
+ last: function() {
+ return this.eq( -1 );
+ },
+
+ slice: function() {
+ return this.pushStack( slice.apply( this, arguments ),
+ "slice", slice.call(arguments).join(",") );
+ },
+
+ map: function( callback ) {
+ return this.pushStack( jQuery.map(this, function( elem, i ) {
+ return callback.call( elem, i, elem );
+ }));
+ },
+
+ end: function() {
+ return this.prevObject || jQuery(null);
+ },
+
+ // For internal use only.
+ // Behaves like an Array's method, not like a jQuery method.
+ push: push,
+ sort: [].sort,
+ splice: [].splice
+};
+
+// Give the init function the jQuery prototype for later instantiation
+jQuery.fn.init.prototype = jQuery.fn;
+
+jQuery.extend = jQuery.fn.extend = function() {
+ // copy reference to target object
+ var target = arguments[0] || {}, i = 1, length = arguments.length, deep = false, options, name, src, copy;
+
+ // Handle a deep copy situation
+ if ( typeof target === "boolean" ) {
+ deep = target;
+ target = arguments[1] || {};
+ // skip the boolean and the target
+ i = 2;
+ }
+
+ // Handle case when target is a string or something (possible in deep copy)
+ if ( typeof target !== "object" && !jQuery.isFunction(target) ) {
+ target = {};
+ }
+
+ // extend jQuery itself if only one argument is passed
+ if ( length === i ) {
+ target = this;
+ --i;
+ }
+
+ for ( ; i < length; i++ ) {
+ // Only deal with non-null/undefined values
+ if ( (options = arguments[ i ]) != null ) {
+ // Extend the base object
+ for ( name in options ) {
+ src = target[ name ];
+ copy = options[ name ];
+
+ // Prevent never-ending loop
+ if ( target === copy ) {
+ continue;
+ }
+
+ // Recurse if we're merging object literal values or arrays
+ if ( deep && copy && ( jQuery.isPlainObject(copy) || jQuery.isArray(copy) ) ) {
+ var clone = src && ( jQuery.isPlainObject(src) || jQuery.isArray(src) ) ? src
+ : jQuery.isArray(copy) ? [] : {};
+
+ // Never move original objects, clone them
+ target[ name ] = jQuery.extend( deep, clone, copy );
+
+ // Don't bring in undefined values
+ } else if ( copy !== undefined ) {
+ target[ name ] = copy;
+ }
+ }
+ }
+ }
+
+ // Return the modified object
+ return target;
+};
+
+jQuery.extend({
+ noConflict: function( deep ) {
+ window.$ = _$;
+
+ if ( deep ) {
+ window.jQuery = _jQuery;
+ }
+
+ return jQuery;
+ },
+
+ // Is the DOM ready to be used? Set to true once it occurs.
+ isReady: false,
+
+ // Handle when the DOM is ready
+ ready: function() {
+ // Make sure that the DOM is not already loaded
+ if ( !jQuery.isReady ) {
+ // Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443).
+ if ( !document.body ) {
+ return setTimeout( jQuery.ready, 13 );
+ }
+
+ // Remember that the DOM is ready
+ jQuery.isReady = true;
+
+ // If there are functions bound, to execute
+ if ( readyList ) {
+ // Execute all of them
+ var fn, i = 0;
+ while ( (fn = readyList[ i++ ]) ) {
+ fn.call( document, jQuery );
+ }
+
+ // Reset the list of functions
+ readyList = null;
+ }
+
+ // Trigger any bound ready events
+ if ( jQuery.fn.triggerHandler ) {
+ jQuery( document ).triggerHandler( "ready" );
+ }
+ }
+ },
+
+ bindReady: function() {
+ if ( readyBound ) {
+ return;
+ }
+
+ readyBound = true;
+
+ // Catch cases where $(document).ready() is called after the
+ // browser event has already occurred.
+ if ( document.readyState === "complete" ) {
+ return jQuery.ready();
+ }
+
+ // Mozilla, Opera and webkit nightlies currently support this event
+ if ( document.addEventListener ) {
+ // Use the handy event callback
+ document.addEventListener( "DOMContentLoaded", DOMContentLoaded, false );
+
+ // A fallback to window.onload, that will always work
+ window.addEventListener( "load", jQuery.ready, false );
+
+ // If IE event model is used
+ } else if ( document.attachEvent ) {
+ // ensure firing before onload,
+ // maybe late but safe also for iframes
+ document.attachEvent("onreadystatechange", DOMContentLoaded);
+
+ // A fallback to window.onload, that will always work
+ window.attachEvent( "onload", jQuery.ready );
+
+ // If IE and not a frame
+ // continually check to see if the document is ready
+ var toplevel = false;
+
+ try {
+ toplevel = window.frameElement == null;
+ } catch(e) {}
+
+ if ( document.documentElement.doScroll && toplevel ) {
+ doScrollCheck();
+ }
+ }
+ },
+
+ // See test/unit/core.js for details concerning isFunction.
+ // Since version 1.3, DOM methods and functions like alert
+ // aren't supported. They return false on IE (#2968).
+ isFunction: function( obj ) {
+ return toString.call(obj) === "[object Function]";
+ },
+
+ isArray: function( obj ) {
+ return toString.call(obj) === "[object Array]";
+ },
+
+ isPlainObject: function( obj ) {
+ // Must be an Object.
+ // Because of IE, we also have to check the presence of the constructor property.
+ // Make sure that DOM nodes and window objects don't pass through, as well
+ if ( !obj || toString.call(obj) !== "[object Object]" || obj.nodeType || obj.setInterval ) {
+ return false;
+ }
+
+ // Not own constructor property must be Object
+ if ( obj.constructor
+ && !hasOwnProperty.call(obj, "constructor")
+ && !hasOwnProperty.call(obj.constructor.prototype, "isPrototypeOf") ) {
+ return false;
+ }
+
+ // Own properties are enumerated firstly, so to speed up,
+ // if last one is own, then all properties are own.
+
+ var key;
+ for ( key in obj ) {}
+
+ return key === undefined || hasOwnProperty.call( obj, key );
+ },
+
+ isEmptyObject: function( obj ) {
+ for ( var name in obj ) {
+ return false;
+ }
+ return true;
+ },
+
+ error: function( msg ) {
+ throw msg;
+ },
+
+ parseJSON: function( data ) {
+ if ( typeof data !== "string" || !data ) {
+ return null;
+ }
+
+ // Make sure leading/trailing whitespace is removed (IE can't handle it)
+ data = jQuery.trim( data );
+
+ // Make sure the incoming data is actual JSON
+ // Logic borrowed from http://json.org/json2.js
+ if ( /^[\],:{}\s]*$/.test(data.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, "@")
+ .replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, "]")
+ .replace(/(?:^|:|,)(?:\s*\[)+/g, "")) ) {
+
+ // Try to use the native JSON parser first
+ return window.JSON && window.JSON.parse ?
+ window.JSON.parse( data ) :
+ (new Function("return " + data))();
+
+ } else {
+ jQuery.error( "Invalid JSON: " + data );
+ }
+ },
+
+ noop: function() {},
+
+ // Evalulates a script in a global context
+ globalEval: function( data ) {
+ if ( data && rnotwhite.test(data) ) {
+ // Inspired by code by Andrea Giammarchi
+ // http://webreflection.blogspot.com/2007/08/global-scope-evaluation-and-dom.html
+ var head = document.getElementsByTagName("head")[0] || document.documentElement,
+ script = document.createElement("script");
+
+ script.type = "text/javascript";
+
+ if ( jQuery.support.scriptEval ) {
+ script.appendChild( document.createTextNode( data ) );
+ } else {
+ script.text = data;
+ }
+
+ // Use insertBefore instead of appendChild to circumvent an IE6 bug.
+ // This arises when a base node is used (#2709).
+ head.insertBefore( script, head.firstChild );
+ head.removeChild( script );
+ }
+ },
+
+ nodeName: function( elem, name ) {
+ return elem.nodeName && elem.nodeName.toUpperCase() === name.toUpperCase();
+ },
+
+ // args is for internal usage only
+ each: function( object, callback, args ) {
+ var name, i = 0,
+ length = object.length,
+ isObj = length === undefined || jQuery.isFunction(object);
+
+ if ( args ) {
+ if ( isObj ) {
+ for ( name in object ) {
+ if ( callback.apply( object[ name ], args ) === false ) {
+ break;
+ }
+ }
+ } else {
+ for ( ; i < length; ) {
+ if ( callback.apply( object[ i++ ], args ) === false ) {
+ break;
+ }
+ }
+ }
+
+ // A special, fast, case for the most common use of each
+ } else {
+ if ( isObj ) {
+ for ( name in object ) {
+ if ( callback.call( object[ name ], name, object[ name ] ) === false ) {
+ break;
+ }
+ }
+ } else {
+ for ( var value = object[0];
+ i < length && callback.call( value, i, value ) !== false; value = object[++i] ) {}
+ }
+ }
+
+ return object;
+ },
+
+ trim: function( text ) {
+ return (text || "").replace( rtrim, "" );
+ },
+
+ // results is for internal usage only
+ makeArray: function( array, results ) {
+ var ret = results || [];
+
+ if ( array != null ) {
+ // The window, strings (and functions) also have 'length'
+ // The extra typeof function check is to prevent crashes
+ // in Safari 2 (See: #3039)
+ if ( array.length == null || typeof array === "string" || jQuery.isFunction(array) || (typeof array !== "function" && array.setInterval) ) {
+ push.call( ret, array );
+ } else {
+ jQuery.merge( ret, array );
+ }
+ }
+
+ return ret;
+ },
+
+ inArray: function( elem, array ) {
+ if ( array.indexOf ) {
+ return array.indexOf( elem );
+ }
+
+ for ( var i = 0, length = array.length; i < length; i++ ) {
+ if ( array[ i ] === elem ) {
+ return i;
+ }
+ }
+
+ return -1;
+ },
+
+ merge: function( first, second ) {
+ var i = first.length, j = 0;
+
+ if ( typeof second.length === "number" ) {
+ for ( var l = second.length; j < l; j++ ) {
+ first[ i++ ] = second[ j ];
+ }
+
+ } else {
+ while ( second[j] !== undefined ) {
+ first[ i++ ] = second[ j++ ];
+ }
+ }
+
+ first.length = i;
+
+ return first;
+ },
+
+ grep: function( elems, callback, inv ) {
+ var ret = [];
+
+ // Go through the array, only saving the items
+ // that pass the validator function
+ for ( var i = 0, length = elems.length; i < length; i++ ) {
+ if ( !inv !== !callback( elems[ i ], i ) ) {
+ ret.push( elems[ i ] );
+ }
+ }
+
+ return ret;
+ },
+
+ // arg is for internal usage only
+ map: function( elems, callback, arg ) {
+ var ret = [], value;
+
+ // Go through the array, translating each of the items to their
+ // new value (or values).
+ for ( var i = 0, length = elems.length; i < length; i++ ) {
+ value = callback( elems[ i ], i, arg );
+
+ if ( value != null ) {
+ ret[ ret.length ] = value;
+ }
+ }
+
+ return ret.concat.apply( [], ret );
+ },
+
+ // A global GUID counter for objects
+ guid: 1,
+
+ proxy: function( fn, proxy, thisObject ) {
+ if ( arguments.length === 2 ) {
+ if ( typeof proxy === "string" ) {
+ thisObject = fn;
+ fn = thisObject[ proxy ];
+ proxy = undefined;
+
+ } else if ( proxy && !jQuery.isFunction( proxy ) ) {
+ thisObject = proxy;
+ proxy = undefined;
+ }
+ }
+
+ if ( !proxy && fn ) {
+ proxy = function() {
+ return fn.apply( thisObject || this, arguments );
+ };
+ }
+
+ // Set the guid of unique handler to the same of original handler, so it can be removed
+ if ( fn ) {
+ proxy.guid = fn.guid = fn.guid || proxy.guid || jQuery.guid++;
+ }
+
+ // So proxy can be declared as an argument
+ return proxy;
+ },
+
+ // Use of jQuery.browser is frowned upon.
+ // More details: http://docs.jquery.com/Utilities/jQuery.browser
+ uaMatch: function( ua ) {
+ ua = ua.toLowerCase();
+
+ var match = /(webkit)[ \/]([\w.]+)/.exec( ua ) ||
+ /(opera)(?:.*version)?[ \/]([\w.]+)/.exec( ua ) ||
+ /(msie) ([\w.]+)/.exec( ua ) ||
+ !/compatible/.test( ua ) && /(mozilla)(?:.*? rv:([\w.]+))?/.exec( ua ) ||
+ [];
+
+ return { browser: match[1] || "", version: match[2] || "0" };
+ },
+
+ browser: {}
+});
+
+browserMatch = jQuery.uaMatch( userAgent );
+if ( browserMatch.browser ) {
+ jQuery.browser[ browserMatch.browser ] = true;
+ jQuery.browser.version = browserMatch.version;
+}
+
+// Deprecated, use jQuery.browser.webkit instead
+if ( jQuery.browser.webkit ) {
+ jQuery.browser.safari = true;
+}
+
+if ( indexOf ) {
+ jQuery.inArray = function( elem, array ) {
+ return indexOf.call( array, elem );
+ };
+}
+
+// All jQuery objects should point back to these
+rootjQuery = jQuery(document);
+
+// Cleanup functions for the document ready method
+if ( document.addEventListener ) {
+ DOMContentLoaded = function() {
+ document.removeEventListener( "DOMContentLoaded", DOMContentLoaded, false );
+ jQuery.ready();
+ };
+
+} else if ( document.attachEvent ) {
+ DOMContentLoaded = function() {
+ // Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443).
+ if ( document.readyState === "complete" ) {
+ document.detachEvent( "onreadystatechange", DOMContentLoaded );
+ jQuery.ready();
+ }
+ };
+}
+
+// The DOM ready check for Internet Explorer
+function doScrollCheck() {
+ if ( jQuery.isReady ) {
+ return;
+ }
+
+ try {
+ // If IE is used, use the trick by Diego Perini
+ // http://javascript.nwbox.com/IEContentLoaded/
+ document.documentElement.doScroll("left");
+ } catch( error ) {
+ setTimeout( doScrollCheck, 1 );
+ return;
+ }
+
+ // and execute any waiting functions
+ jQuery.ready();
+}
+
+function evalScript( i, elem ) {
+ if ( elem.src ) {
+ jQuery.ajax({
+ url: elem.src,
+ async: false,
+ dataType: "script"
+ });
+ } else {
+ jQuery.globalEval( elem.text || elem.textContent || elem.innerHTML || "" );
+ }
+
+ if ( elem.parentNode ) {
+ elem.parentNode.removeChild( elem );
+ }
+}
+
+// Mutifunctional method to get and set values to a collection
+// The value/s can be optionally by executed if its a function
+function access( elems, key, value, exec, fn, pass ) {
+ var length = elems.length;
+
+ // Setting many attributes
+ if ( typeof key === "object" ) {
+ for ( var k in key ) {
+ access( elems, k, key[k], exec, fn, value );
+ }
+ return elems;
+ }
+
+ // Setting one attribute
+ if ( value !== undefined ) {
+ // Optionally, function values get executed if exec is true
+ exec = !pass && exec && jQuery.isFunction(value);
+
+ for ( var i = 0; i < length; i++ ) {
+ fn( elems[i], key, exec ? value.call( elems[i], i, fn( elems[i], key ) ) : value, pass );
+ }
+
+ return elems;
+ }
+
+ // Getting an attribute
+ return length ? fn( elems[0], key ) : undefined;
+}
+
+function now() {
+ return (new Date).getTime();
+}
+(function() {
+
+ jQuery.support = {};
+
+ var root = document.documentElement,
+ script = document.createElement("script"),
+ div = document.createElement("div"),
+ id = "script" + now();
+
+ div.style.display = "none";
+ div.innerHTML = " <link/><table></table><a href='/a' style='color:red;float:left;opacity:.55;'>a</a><input type='checkbox'/>";
+
+ var all = div.getElementsByTagName("*"),
+ a = div.getElementsByTagName("a")[0];
+
+ // Can't get basic test support
+ if ( !all || !all.length || !a ) {
+ return;
+ }
+
+ jQuery.support = {
+ // IE strips leading whitespace when .innerHTML is used
+ leadingWhitespace: div.firstChild.nodeType === 3,
+
+ // Make sure that tbody elements aren't automatically inserted
+ // IE will insert them into empty tables
+ tbody: !div.getElementsByTagName("tbody").length,
+
+ // Make sure that link elements get serialized correctly by innerHTML
+ // This requires a wrapper element in IE
+ htmlSerialize: !!div.getElementsByTagName("link").length,
+
+ // Get the style information from getAttribute
+ // (IE uses .cssText insted)
+ style: /red/.test( a.getAttribute("style") ),
+
+ // Make sure that URLs aren't manipulated
+ // (IE normalizes it by default)
+ hrefNormalized: a.getAttribute("href") === "/a",
+
+ // Make sure that element opacity exists
+ // (IE uses filter instead)
+ // Use a regex to work around a WebKit issue. See #5145
+ opacity: /^0.55$/.test( a.style.opacity ),
+
+ // Verify style float existence
+ // (IE uses styleFloat instead of cssFloat)
+ cssFloat: !!a.style.cssFloat,
+
+ // Make sure that if no value is specified for a checkbox
+ // that it defaults to "on".
+ // (WebKit defaults to "" instead)
+ checkOn: div.getElementsByTagName("input")[0].value === "on",
+
+ // Make sure that a selected-by-default option has a working selected property.
+ // (WebKit defaults to false instead of true, IE too, if it's in an optgroup)
+ optSelected: document.createElement("select").appendChild( document.createElement("option") ).selected,
+
+ parentNode: div.removeChild( div.appendChild( document.createElement("div") ) ).parentNode === null,
+
+ // Will be defined later
+ deleteExpando: true,
+ checkClone: false,
+ scriptEval: false,
+ noCloneEvent: true,
+ boxModel: null
+ };
+
+ script.type = "text/javascript";
+ try {
+ script.appendChild( document.createTextNode( "window." + id + "=1;" ) );
+ } catch(e) {}
+
+ root.insertBefore( script, root.firstChild );
+
+ // Make sure that the execution of code works by injecting a script
+ // tag with appendChild/createTextNode
+ // (IE doesn't support this, fails, and uses .text instead)
+ if ( window[ id ] ) {
+ jQuery.support.scriptEval = true;
+ delete window[ id ];
+ }
+
+ // Test to see if it's possible to delete an expando from an element
+ // Fails in Internet Explorer
+ try {
+ delete script.test;
+
+ } catch(e) {
+ jQuery.support.deleteExpando = false;
+ }
+
+ root.removeChild( script );
+
+ if ( div.attachEvent && div.fireEvent ) {
+ div.attachEvent("onclick", function click() {
+ // Cloning a node shouldn't copy over any
+ // bound event handlers (IE does this)
+ jQuery.support.noCloneEvent = false;
+ div.detachEvent("onclick", click);
+ });
+ div.cloneNode(true).fireEvent("onclick");
+ }
+
+ div = document.createElement("div");
+ div.innerHTML = "<input type='radio' name='radiotest' checked='checked'/>";
+
+ var fragment = document.createDocumentFragment();
+ fragment.appendChild( div.firstChild );
+
+ // WebKit doesn't clone checked state correctly in fragments
+ jQuery.support.checkClone = fragment.cloneNode(true).cloneNode(true).lastChild.checked;
+
+ // Figure out if the W3C box model works as expected
+ // document.body must exist before we can do this
+ jQuery(function() {
+ var div = document.createElement("div");
+ div.style.width = div.style.paddingLeft = "1px";
+
+ document.body.appendChild( div );
+ jQuery.boxModel = jQuery.support.boxModel = div.offsetWidth === 2;
+ document.body.removeChild( div ).style.display = 'none';
+
+ div = null;
+ });
+
+ // Technique from Juriy Zaytsev
+ // http://thinkweb2.com/projects/prototype/detecting-event-support-without-browser-sniffing/
+ var eventSupported = function( eventName ) {
+ var el = document.createElement("div");
+ eventName = "on" + eventName;
+
+ var isSupported = (eventName in el);
+ if ( !isSupported ) {
+ el.setAttribute(eventName, "return;");
+ isSupported = typeof el[eventName] === "function";
+ }
+ el = null;
+
+ return isSupported;
+ };
+
+ jQuery.support.submitBubbles = eventSupported("submit");
+ jQuery.support.changeBubbles = eventSupported("change");
+
+ // release memory in IE
+ root = script = div = all = a = null;
+})();
+
+jQuery.props = {
+ "for": "htmlFor",
+ "class": "className",
+ readonly: "readOnly",
+ maxlength: "maxLength",
+ cellspacing: "cellSpacing",
+ rowspan: "rowSpan",
+ colspan: "colSpan",
+ tabindex: "tabIndex",
+ usemap: "useMap",
+ frameborder: "frameBorder"
+};
+var expando = "jQuery" + now(), uuid = 0, windowData = {};
+
+jQuery.extend({
+ cache: {},
+
+ expando:expando,
+
+ // The following elements throw uncatchable exceptions if you
+ // attempt to add expando properties to them.
+ noData: {
+ "embed": true,
+ "object": true,
+ "applet": true
+ },
+
+ data: function( elem, name, data ) {
+ if ( elem.nodeName && jQuery.noData[elem.nodeName.toLowerCase()] ) {
+ return;
+ }
+
+ elem = elem == window ?
+ windowData :
+ elem;
+
+ var id = elem[ expando ], cache = jQuery.cache, thisCache;
+
+ if ( !id && typeof name === "string" && data === undefined ) {
+ return null;
+ }
+
+ // Compute a unique ID for the element
+ if ( !id ) {
+ id = ++uuid;
+ }
+
+ // Avoid generating a new cache unless none exists and we
+ // want to manipulate it.
+ if ( typeof name === "object" ) {
+ elem[ expando ] = id;
+ thisCache = cache[ id ] = jQuery.extend(true, {}, name);
+
+ } else if ( !cache[ id ] ) {
+ elem[ expando ] = id;
+ cache[ id ] = {};
+ }
+
+ thisCache = cache[ id ];
+
+ // Prevent overriding the named cache with undefined values
+ if ( data !== undefined ) {
+ thisCache[ name ] = data;
+ }
+
+ return typeof name === "string" ? thisCache[ name ] : thisCache;
+ },
+
+ removeData: function( elem, name ) {
+ if ( elem.nodeName && jQuery.noData[elem.nodeName.toLowerCase()] ) {
+ return;
+ }
+
+ elem = elem == window ?
+ windowData :
+ elem;
+
+ var id = elem[ expando ], cache = jQuery.cache, thisCache = cache[ id ];
+
+ // If we want to remove a specific section of the element's data
+ if ( name ) {
+ if ( thisCache ) {
+ // Remove the section of cache data
+ delete thisCache[ name ];
+
+ // If we've removed all the data, remove the element's cache
+ if ( jQuery.isEmptyObject(thisCache) ) {
+ jQuery.removeData( elem );
+ }
+ }
+
+ // Otherwise, we want to remove all of the element's data
+ } else {
+ if ( jQuery.support.deleteExpando ) {
+ delete elem[ jQuery.expando ];
+
+ } else if ( elem.removeAttribute ) {
+ elem.removeAttribute( jQuery.expando );
+ }
+
+ // Completely remove the data cache
+ delete cache[ id ];
+ }
+ }
+});
+
+jQuery.fn.extend({
+ data: function( key, value ) {
+ if ( typeof key === "undefined" && this.length ) {
+ return jQuery.data( this[0] );
+
+ } else if ( typeof key === "object" ) {
+ return this.each(function() {
+ jQuery.data( this, key );
+ });
+ }
+
+ var parts = key.split(".");
+ parts[1] = parts[1] ? "." + parts[1] : "";
+
+ if ( value === undefined ) {
+ var data = this.triggerHandler("getData" + parts[1] + "!", [parts[0]]);
+
+ if ( data === undefined && this.length ) {
+ data = jQuery.data( this[0], key );
+ }
+ return data === undefined && parts[1] ?
+ this.data( parts[0] ) :
+ data;
+ } else {
+ return this.trigger("setData" + parts[1] + "!", [parts[0], value]).each(function() {
+ jQuery.data( this, key, value );
+ });
+ }
+ },
+
+ removeData: function( key ) {
+ return this.each(function() {
+ jQuery.removeData( this, key );
+ });
+ }
+});
+jQuery.extend({
+ queue: function( elem, type, data ) {
+ if ( !elem ) {
+ return;
+ }
+
+ type = (type || "fx") + "queue";
+ var q = jQuery.data( elem, type );
+
+ // Speed up dequeue by getting out quickly if this is just a lookup
+ if ( !data ) {
+ return q || [];
+ }
+
+ if ( !q || jQuery.isArray(data) ) {
+ q = jQuery.data( elem, type, jQuery.makeArray(data) );
+
+ } else {
+ q.push( data );
+ }
+
+ return q;
+ },
+
+ dequeue: function( elem, type ) {
+ type = type || "fx";
+
+ var queue = jQuery.queue( elem, type ), fn = queue.shift();
+
+ // If the fx queue is dequeued, always remove the progress sentinel
+ if ( fn === "inprogress" ) {
+ fn = queue.shift();
+ }
+
+ if ( fn ) {
+ // Add a progress sentinel to prevent the fx queue from being
+ // automatically dequeued
+ if ( type === "fx" ) {
+ queue.unshift("inprogress");
+ }
+
+ fn.call(elem, function() {
+ jQuery.dequeue(elem, type);
+ });
+ }
+ }
+});
+
+jQuery.fn.extend({
+ queue: function( type, data ) {
+ if ( typeof type !== "string" ) {
+ data = type;
+ type = "fx";
+ }
+
+ if ( data === undefined ) {
+ return jQuery.queue( this[0], type );
+ }
+ return this.each(function( i, elem ) {
+ var queue = jQuery.queue( this, type, data );
+
+ if ( type === "fx" && queue[0] !== "inprogress" ) {
+ jQuery.dequeue( this, type );
+ }
+ });
+ },
+ dequeue: function( type ) {
+ return this.each(function() {
+ jQuery.dequeue( this, type );
+ });
+ },
+
+ // Based off of the plugin by Clint Helfers, with permission.
+ // http://blindsignals.com/index.php/2009/07/jquery-delay/
+ delay: function( time, type ) {
+ time = jQuery.fx ? jQuery.fx.speeds[time] || time : time;
+ type = type || "fx";
+
+ return this.queue( type, function() {
+ var elem = this;
+ setTimeout(function() {
+ jQuery.dequeue( elem, type );
+ }, time );
+ });
+ },
+
+ clearQueue: function( type ) {
+ return this.queue( type || "fx", [] );
+ }
+});
+var rclass = /[\n\t]/g,
+ rspace = /\s+/,
+ rreturn = /\r/g,
+ rspecialurl = /href|src|style/,
+ rtype = /(button|input)/i,
+ rfocusable = /(button|input|object|select|textarea)/i,
+ rclickable = /^(a|area)$/i,
+ rradiocheck = /radio|checkbox/;
+
+jQuery.fn.extend({
+ attr: function( name, value ) {
+ return access( this, name, value, true, jQuery.attr );
+ },
+
+ removeAttr: function( name, fn ) {
+ return this.each(function(){
+ jQuery.attr( this, name, "" );
+ if ( this.nodeType === 1 ) {
+ this.removeAttribute( name );
+ }
+ });
+ },
+
+ addClass: function( value ) {
+ if ( jQuery.isFunction(value) ) {
+ return this.each(function(i) {
+ var self = jQuery(this);
+ self.addClass( value.call(this, i, self.attr("class")) );
+ });
+ }
+
+ if ( value && typeof value === "string" ) {
+ var classNames = (value || "").split( rspace );
+
+ for ( var i = 0, l = this.length; i < l; i++ ) {
+ var elem = this[i];
+
+ if ( elem.nodeType === 1 ) {
+ if ( !elem.className ) {
+ elem.className = value;
+
+ } else {
+ var className = " " + elem.className + " ", setClass = elem.className;
+ for ( var c = 0, cl = classNames.length; c < cl; c++ ) {
+ if ( className.indexOf( " " + classNames[c] + " " ) < 0 ) {
+ setClass += " " + classNames[c];
+ }
+ }
+ elem.className = jQuery.trim( setClass );
+ }
+ }
+ }
+ }
+
+ return this;
+ },
+
+ removeClass: function( value ) {
+ if ( jQuery.isFunction(value) ) {
+ return this.each(function(i) {
+ var self = jQuery(this);
+ self.removeClass( value.call(this, i, self.attr("class")) );
+ });
+ }
+
+ if ( (value && typeof value === "string") || value === undefined ) {
+ var classNames = (value || "").split(rspace);
+
+ for ( var i = 0, l = this.length; i < l; i++ ) {
+ var elem = this[i];
+
+ if ( elem.nodeType === 1 && elem.className ) {
+ if ( value ) {
+ var className = (" " + elem.className + " ").replace(rclass, " ");
+ for ( var c = 0, cl = classNames.length; c < cl; c++ ) {
+ className = className.replace(" " + classNames[c] + " ", " ");
+ }
+ elem.className = jQuery.trim( className );
+
+ } else {
+ elem.className = "";
+ }
+ }
+ }
+ }
+
+ return this;
+ },
+
+ toggleClass: function( value, stateVal ) {
+ var type = typeof value, isBool = typeof stateVal === "boolean";
+
+ if ( jQuery.isFunction( value ) ) {
+ return this.each(function(i) {
+ var self = jQuery(this);
+ self.toggleClass( value.call(this, i, self.attr("class"), stateVal), stateVal );
+ });
+ }
+
+ return this.each(function() {
+ if ( type === "string" ) {
+ // toggle individual class names
+ var className, i = 0, self = jQuery(this),
+ state = stateVal,
+ classNames = value.split( rspace );
+
+ while ( (className = classNames[ i++ ]) ) {
+ // check each className given, space seperated list
+ state = isBool ? state : !self.hasClass( className );
+ self[ state ? "addClass" : "removeClass" ]( className );
+ }
+
+ } else if ( type === "undefined" || type === "boolean" ) {
+ if ( this.className ) {
+ // store className if set
+ jQuery.data( this, "__className__", this.className );
+ }
+
+ // toggle whole className
+ this.className = this.className || value === false ? "" : jQuery.data( this, "__className__" ) || "";
+ }
+ });
+ },
+
+ hasClass: function( selector ) {
+ var className = " " + selector + " ";
+ for ( var i = 0, l = this.length; i < l; i++ ) {
+ if ( (" " + this[i].className + " ").replace(rclass, " ").indexOf( className ) > -1 ) {
+ return true;
+ }
+ }
+
+ return false;
+ },
+
+ val: function( value ) {
+ if ( value === undefined ) {
+ var elem = this[0];
+
+ if ( elem ) {
+ if ( jQuery.nodeName( elem, "option" ) ) {
+ return (elem.attributes.value || {}).specified ? elem.value : elem.text;
+ }
+
+ // We need to handle select boxes special
+ if ( jQuery.nodeName( elem, "select" ) ) {
+ var index = elem.selectedIndex,
+ values = [],
+ options = elem.options,
+ one = elem.type === "select-one";
+
+ // Nothing was selected
+ if ( index < 0 ) {
+ return null;
+ }
+
+ // Loop through all the selected options
+ for ( var i = one ? index : 0, max = one ? index + 1 : options.length; i < max; i++ ) {
+ var option = options[ i ];
+
+ if ( option.selected ) {
+ // Get the specifc value for the option
+ value = jQuery(option).val();
+
+ // We don't need an array for one selects
+ if ( one ) {
+ return value;
+ }
+
+ // Multi-Selects return an array
+ values.push( value );
+ }
+ }
+
+ return values;
+ }
+
+ // Handle the case where in Webkit "" is returned instead of "on" if a value isn't specified
+ if ( rradiocheck.test( elem.type ) && !jQuery.support.checkOn ) {
+ return elem.getAttribute("value") === null ? "on" : elem.value;
+ }
+
+
+ // Everything else, we just grab the value
+ return (elem.value || "").replace(rreturn, "");
+
+ }
+
+ return undefined;
+ }
+
+ var isFunction = jQuery.isFunction(value);
+
+ return this.each(function(i) {
+ var self = jQuery(this), val = value;
+
+ if ( this.nodeType !== 1 ) {
+ return;
+ }
+
+ if ( isFunction ) {
+ val = value.call(this, i, self.val());
+ }
+
+ // Typecast each time if the value is a Function and the appended
+ // value is therefore different each time.
+ if ( typeof val === "number" ) {
+ val += "";
+ }
+
+ if ( jQuery.isArray(val) && rradiocheck.test( this.type ) ) {
+ this.checked = jQuery.inArray( self.val(), val ) >= 0;
+
+ } else if ( jQuery.nodeName( this, "select" ) ) {
+ var values = jQuery.makeArray(val);
+
+ jQuery( "option", this ).each(function() {
+ this.selected = jQuery.inArray( jQuery(this).val(), values ) >= 0;
+ });
+
+ if ( !values.length ) {
+ this.selectedIndex = -1;
+ }
+
+ } else {
+ this.value = val;
+ }
+ });
+ }
+});
+
+jQuery.extend({
+ attrFn: {
+ val: true,
+ css: true,
+ html: true,
+ text: true,
+ data: true,
+ width: true,
+ height: true,
+ offset: true
+ },
+
+ attr: function( elem, name, value, pass ) {
+ // don't set attributes on text and comment nodes
+ if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 ) {
+ return undefined;
+ }
+
+ if ( pass && name in jQuery.attrFn ) {
+ return jQuery(elem)[name](value);
+ }
+
+ var notxml = elem.nodeType !== 1 || !jQuery.isXMLDoc( elem ),
+ // Whether we are setting (or getting)
+ set = value !== undefined;
+
+ // Try to normalize/fix the name
+ name = notxml && jQuery.props[ name ] || name;
+
+ // Only do all the following if this is a node (faster for style)
+ if ( elem.nodeType === 1 ) {
+ // These attributes require special treatment
+ var special = rspecialurl.test( name );
+
+ // Safari mis-reports the default selected property of an option
+ // Accessing the parent's selectedIndex property fixes it
+ if ( name === "selected" && !jQuery.support.optSelected ) {
+ var parent = elem.parentNode;
+ if ( parent ) {
+ parent.selectedIndex;
+
+ // Make sure that it also works with optgroups, see #5701
+ if ( parent.parentNode ) {
+ parent.parentNode.selectedIndex;
+ }
+ }
+ }
+
+ // If applicable, access the attribute via the DOM 0 way
+ if ( name in elem && notxml && !special ) {
+ if ( set ) {
+ // We can't allow the type property to be changed (since it causes problems in IE)
+ if ( name === "type" && rtype.test( elem.nodeName ) && elem.parentNode ) {
+ jQuery.error( "type property can't be changed" );
+ }
+
+ elem[ name ] = value;
+ }
+
+ // browsers index elements by id/name on forms, give priority to attributes.
+ if ( jQuery.nodeName( elem, "form" ) && elem.getAttributeNode(name) ) {
+ return elem.getAttributeNode( name ).nodeValue;
+ }
+
+ // elem.tabIndex doesn't always return the correct value when it hasn't been explicitly set
+ // http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/
+ if ( name === "tabIndex" ) {
+ var attributeNode = elem.getAttributeNode( "tabIndex" );
+
+ return attributeNode && attributeNode.specified ?
+ attributeNode.value :
+ rfocusable.test( elem.nodeName ) || rclickable.test( elem.nodeName ) && elem.href ?
+ 0 :
+ undefined;
+ }
+
+ return elem[ name ];
+ }
+
+ if ( !jQuery.support.style && notxml && name === "style" ) {
+ if ( set ) {
+ elem.style.cssText = "" + value;
+ }
+
+ return elem.style.cssText;
+ }
+
+ if ( set ) {
+ // convert the value to a string (all browsers do this but IE) see #1070
+ elem.setAttribute( name, "" + value );
+ }
+
+ var attr = !jQuery.support.hrefNormalized && notxml && special ?
+ // Some attributes require a special call on IE
+ elem.getAttribute( name, 2 ) :
+ elem.getAttribute( name );
+
+ // Non-existent attributes return null, we normalize to undefined
+ return attr === null ? undefined : attr;
+ }
+
+ // elem is actually elem.style ... set the style
+ // Using attr for specific style information is now deprecated. Use style instead.
+ return jQuery.style( elem, name, value );
+ }
+});
+var rnamespaces = /\.(.*)$/,
+ fcleanup = function( nm ) {
+ return nm.replace(/[^\w\s\.\|`]/g, function( ch ) {
+ return "\\" + ch;
+ });
+ };
+
+/*
+ * A number of helper functions used for managing events.
+ * Many of the ideas behind this code originated from
+ * Dean Edwards' addEvent library.
+ */
+jQuery.event = {
+
+ // Bind an event to an element
+ // Original by Dean Edwards
+ add: function( elem, types, handler, data ) {
+ if ( elem.nodeType === 3 || elem.nodeType === 8 ) {
+ return;
+ }
+
+ // For whatever reason, IE has trouble passing the window object
+ // around, causing it to be cloned in the process
+ if ( elem.setInterval && ( elem !== window && !elem.frameElement ) ) {
+ elem = window;
+ }
+
+ var handleObjIn, handleObj;
+
+ if ( handler.handler ) {
+ handleObjIn = handler;
+ handler = handleObjIn.handler;
+ }
+
+ // Make sure that the function being executed has a unique ID
+ if ( !handler.guid ) {
+ handler.guid = jQuery.guid++;
+ }
+
+ // Init the element's event structure
+ var elemData = jQuery.data( elem );
+
+ // If no elemData is found then we must be trying to bind to one of the
+ // banned noData elements
+ if ( !elemData ) {
+ return;
+ }
+
+ var events = elemData.events = elemData.events || {},
+ eventHandle = elemData.handle, eventHandle;
+
+ if ( !eventHandle ) {
+ elemData.handle = eventHandle = function() {
+ // Handle the second event of a trigger and when
+ // an event is called after a page has unloaded
+ return typeof jQuery !== "undefined" && !jQuery.event.triggered ?
+ jQuery.event.handle.apply( eventHandle.elem, arguments ) :
+ undefined;
+ };
+ }
+
+ // Add elem as a property of the handle function
+ // This is to prevent a memory leak with non-native events in IE.
+ eventHandle.elem = elem;
+
+ // Handle multiple events separated by a space
+ // jQuery(...).bind("mouseover mouseout", fn);
+ types = types.split(" ");
+
+ var type, i = 0, namespaces;
+
+ while ( (type = types[ i++ ]) ) {
+ handleObj = handleObjIn ?
+ jQuery.extend({}, handleObjIn) :
+ { handler: handler, data: data };
+
+ // Namespaced event handlers
+ if ( type.indexOf(".") > -1 ) {
+ namespaces = type.split(".");
+ type = namespaces.shift();
+ handleObj.namespace = namespaces.slice(0).sort().join(".");
+
+ } else {
+ namespaces = [];
+ handleObj.namespace = "";
+ }
+
+ handleObj.type = type;
+ handleObj.guid = handler.guid;
+
+ // Get the current list of functions bound to this event
+ var handlers = events[ type ],
+ special = jQuery.event.special[ type ] || {};
+
+ // Init the event handler queue
+ if ( !handlers ) {
+ handlers = events[ type ] = [];
+
+ // Check for a special event handler
+ // Only use addEventListener/attachEvent if the special
+ // events handler returns false
+ if ( !special.setup || special.setup.call( elem, data, namespaces, eventHandle ) === false ) {
+ // Bind the global event handler to the element
+ if ( elem.addEventListener ) {
+ elem.addEventListener( type, eventHandle, false );
+
+ } else if ( elem.attachEvent ) {
+ elem.attachEvent( "on" + type, eventHandle );
+ }
+ }
+ }
+
+ if ( special.add ) {
+ special.add.call( elem, handleObj );
+
+ if ( !handleObj.handler.guid ) {
+ handleObj.handler.guid = handler.guid;
+ }
+ }
+
+ // Add the function to the element's handler list
+ handlers.push( handleObj );
+
+ // Keep track of which events have been used, for global triggering
+ jQuery.event.global[ type ] = true;
+ }
+
+ // Nullify elem to prevent memory leaks in IE
+ elem = null;
+ },
+
+ global: {},
+
+ // Detach an event or set of events from an element
+ remove: function( elem, types, handler, pos ) {
+ // don't do events on text and comment nodes
+ if ( elem.nodeType === 3 || elem.nodeType === 8 ) {
+ return;
+ }
+
+ var ret, type, fn, i = 0, all, namespaces, namespace, special, eventType, handleObj, origType,
+ elemData = jQuery.data( elem ),
+ events = elemData && elemData.events;
+
+ if ( !elemData || !events ) {
+ return;
+ }
+
+ // types is actually an event object here
+ if ( types && types.type ) {
+ handler = types.handler;
+ types = types.type;
+ }
+
+ // Unbind all events for the element
+ if ( !types || typeof types === "string" && types.charAt(0) === "." ) {
+ types = types || "";
+
+ for ( type in events ) {
+ jQuery.event.remove( elem, type + types );
+ }
+
+ return;
+ }
+
+ // Handle multiple events separated by a space
+ // jQuery(...).unbind("mouseover mouseout", fn);
+ types = types.split(" ");
+
+ while ( (type = types[ i++ ]) ) {
+ origType = type;
+ handleObj = null;
+ all = type.indexOf(".") < 0;
+ namespaces = [];
+
+ if ( !all ) {
+ // Namespaced event handlers
+ namespaces = type.split(".");
+ type = namespaces.shift();
+
+ namespace = new RegExp("(^|\\.)" +
+ jQuery.map( namespaces.slice(0).sort(), fcleanup ).join("\\.(?:.*\\.)?") + "(\\.|$)")
+ }
+
+ eventType = events[ type ];
+
+ if ( !eventType ) {
+ continue;
+ }
+
+ if ( !handler ) {
+ for ( var j = 0; j < eventType.length; j++ ) {
+ handleObj = eventType[ j ];
+
+ if ( all || namespace.test( handleObj.namespace ) ) {
+ jQuery.event.remove( elem, origType, handleObj.handler, j );
+ eventType.splice( j--, 1 );
+ }
+ }
+
+ continue;
+ }
+
+ special = jQuery.event.special[ type ] || {};
+
+ for ( var j = pos || 0; j < eventType.length; j++ ) {
+ handleObj = eventType[ j ];
+
+ if ( handler.guid === handleObj.guid ) {
+ // remove the given handler for the given type
+ if ( all || namespace.test( handleObj.namespace ) ) {
+ if ( pos == null ) {
+ eventType.splice( j--, 1 );
+ }
+
+ if ( special.remove ) {
+ special.remove.call( elem, handleObj );
+ }
+ }
+
+ if ( pos != null ) {
+ break;
+ }
+ }
+ }
+
+ // remove generic event handler if no more handlers exist
+ if ( eventType.length === 0 || pos != null && eventType.length === 1 ) {
+ if ( !special.teardown || special.teardown.call( elem, namespaces ) === false ) {
+ removeEvent( elem, type, elemData.handle );
+ }
+
+ ret = null;
+ delete events[ type ];
+ }
+ }
+
+ // Remove the expando if it's no longer used
+ if ( jQuery.isEmptyObject( events ) ) {
+ var handle = elemData.handle;
+ if ( handle ) {
+ handle.elem = null;
+ }
+
+ delete elemData.events;
+ delete elemData.handle;
+
+ if ( jQuery.isEmptyObject( elemData ) ) {
+ jQuery.removeData( elem );
+ }
+ }
+ },
+
+ // bubbling is internal
+ trigger: function( event, data, elem /*, bubbling */ ) {
+ // Event object or event type
+ var type = event.type || event,
+ bubbling = arguments[3];
+
+ if ( !bubbling ) {
+ event = typeof event === "object" ?
+ // jQuery.Event object
+ event[expando] ? event :
+ // Object literal
+ jQuery.extend( jQuery.Event(type), event ) :
+ // Just the event type (string)
+ jQuery.Event(type);
+
+ if ( type.indexOf("!") >= 0 ) {
+ event.type = type = type.slice(0, -1);
+ event.exclusive = true;
+ }
+
+ // Handle a global trigger
+ if ( !elem ) {
+ // Don't bubble custom events when global (to avoid too much overhead)
+ event.stopPropagation();
+
+ // Only trigger if we've ever bound an event for it
+ if ( jQuery.event.global[ type ] ) {
+ jQuery.each( jQuery.cache, function() {
+ if ( this.events && this.events[type] ) {
+ jQuery.event.trigger( event, data, this.handle.elem );
+ }
+ });
+ }
+ }
+
+ // Handle triggering a single element
+
+ // don't do events on text and comment nodes
+ if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 ) {
+ return undefined;
+ }
+
+ // Clean up in case it is reused
+ event.result = undefined;
+ event.target = elem;
+
+ // Clone the incoming data, if any
+ data = jQuery.makeArray( data );
+ data.unshift( event );
+ }
+
+ event.currentTarget = elem;
+
+ // Trigger the event, it is assumed that "handle" is a function
+ var handle = jQuery.data( elem, "handle" );
+ if ( handle ) {
+ handle.apply( elem, data );
+ }
+
+ var parent = elem.parentNode || elem.ownerDocument;
+
+ // Trigger an inline bound script
+ try {
+ if ( !(elem && elem.nodeName && jQuery.noData[elem.nodeName.toLowerCase()]) ) {
+ if ( elem[ "on" + type ] && elem[ "on" + type ].apply( elem, data ) === false ) {
+ event.result = false;
+ }
+ }
+
+ // prevent IE from throwing an error for some elements with some event types, see #3533
+ } catch (e) {}
+
+ if ( !event.isPropagationStopped() && parent ) {
+ jQuery.event.trigger( event, data, parent, true );
+
+ } else if ( !event.isDefaultPrevented() ) {
+ var target = event.target, old,
+ isClick = jQuery.nodeName(target, "a") && type === "click",
+ special = jQuery.event.special[ type ] || {};
+
+ if ( (!special._default || special._default.call( elem, event ) === false) &&
+ !isClick && !(target && target.nodeName && jQuery.noData[target.nodeName.toLowerCase()]) ) {
+
+ try {
+ if ( target[ type ] ) {
+ // Make sure that we don't accidentally re-trigger the onFOO events
+ old = target[ "on" + type ];
+
+ if ( old ) {
+ target[ "on" + type ] = null;
+ }
+
+ jQuery.event.triggered = true;
+ target[ type ]();
+ }
+
+ // prevent IE from throwing an error for some elements with some event types, see #3533
+ } catch (e) {}
+
+ if ( old ) {
+ target[ "on" + type ] = old;
+ }
+
+ jQuery.event.triggered = false;
+ }
+ }
+ },
+
+ handle: function( event ) {
+ var all, handlers, namespaces, namespace, events;
+
+ event = arguments[0] = jQuery.event.fix( event || window.event );
+ event.currentTarget = this;
+
+ // Namespaced event handlers
+ all = event.type.indexOf(".") < 0 && !event.exclusive;
+
+ if ( !all ) {
+ namespaces = event.type.split(".");
+ event.type = namespaces.shift();
+ namespace = new RegExp("(^|\\.)" + namespaces.slice(0).sort().join("\\.(?:.*\\.)?") + "(\\.|$)");
+ }
+
+ var events = jQuery.data(this, "events"), handlers = events[ event.type ];
+
+ if ( events && handlers ) {
+ // Clone the handlers to prevent manipulation
+ handlers = handlers.slice(0);
+
+ for ( var j = 0, l = handlers.length; j < l; j++ ) {
+ var handleObj = handlers[ j ];
+
+ // Filter the functions by class
+ if ( all || namespace.test( handleObj.namespace ) ) {
+ // Pass in a reference to the handler function itself
+ // So that we can later remove it
+ event.handler = handleObj.handler;
+ event.data = handleObj.data;
+ event.handleObj = handleObj;
+
+ var ret = handleObj.handler.apply( this, arguments );
+
+ if ( ret !== undefined ) {
+ event.result = ret;
+ if ( ret === false ) {
+ event.preventDefault();
+ event.stopPropagation();
+ }
+ }
+
+ if ( event.isImmediatePropagationStopped() ) {
+ break;
+ }
+ }
+ }
+ }
+
+ return event.result;
+ },
+
+ props: "altKey attrChange attrName bubbles button cancelable charCode clientX clientY ctrlKey currentTarget data detail eventPhase fromElement handler keyCode layerX layerY metaKey newValue offsetX offsetY originalTarget pageX pageY prevValue relatedNode relatedTarget screenX screenY shiftKey srcElement target toElement view wheelDelta which".split(" "),
+
+ fix: function( event ) {
+ if ( event[ expando ] ) {
+ return event;
+ }
+
+ // store a copy of the original event object
+ // and "clone" to set read-only properties
+ var originalEvent = event;
+ event = jQuery.Event( originalEvent );
+
+ for ( var i = this.props.length, prop; i; ) {
+ prop = this.props[ --i ];
+ event[ prop ] = originalEvent[ prop ];
+ }
+
+ // Fix target property, if necessary
+ if ( !event.target ) {
+ event.target = event.srcElement || document; // Fixes #1925 where srcElement might not be defined either
+ }
+
+ // check if target is a textnode (safari)
+ if ( event.target.nodeType === 3 ) {
+ event.target = event.target.parentNode;
+ }
+
+ // Add relatedTarget, if necessary
+ if ( !event.relatedTarget && event.fromElement ) {
+ event.relatedTarget = event.fromElement === event.target ? event.toElement : event.fromElement;
+ }
+
+ // Calculate pageX/Y if missing and clientX/Y available
+ if ( event.pageX == null && event.clientX != null ) {
+ var doc = document.documentElement, body = document.body;
+ event.pageX = event.clientX + (doc && doc.scrollLeft || body && body.scrollLeft || 0) - (doc && doc.clientLeft || body && body.clientLeft || 0);
+ event.pageY = event.clientY + (doc && doc.scrollTop || body && body.scrollTop || 0) - (doc && doc.clientTop || body && body.clientTop || 0);
+ }
+
+ // Add which for key events
+ if ( !event.which && ((event.charCode || event.charCode === 0) ? event.charCode : event.keyCode) ) {
+ event.which = event.charCode || event.keyCode;
+ }
+
+ // Add metaKey to non-Mac browsers (use ctrl for PC's and Meta for Macs)
+ if ( !event.metaKey && event.ctrlKey ) {
+ event.metaKey = event.ctrlKey;
+ }
+
+ // Add which for click: 1 === left; 2 === middle; 3 === right
+ // Note: button is not normalized, so don't use it
+ if ( !event.which && event.button !== undefined ) {
+ event.which = (event.button & 1 ? 1 : ( event.button & 2 ? 3 : ( event.button & 4 ? 2 : 0 ) ));
+ }
+
+ return event;
+ },
+
+ // Deprecated, use jQuery.guid instead
+ guid: 1E8,
+
+ // Deprecated, use jQuery.proxy instead
+ proxy: jQuery.proxy,
+
+ special: {
+ ready: {
+ // Make sure the ready event is setup
+ setup: jQuery.bindReady,
+ teardown: jQuery.noop
+ },
+
+ live: {
+ add: function( handleObj ) {
+ jQuery.event.add( this, handleObj.origType, jQuery.extend({}, handleObj, {handler: liveHandler}) );
+ },
+
+ remove: function( handleObj ) {
+ var remove = true,
+ type = handleObj.origType.replace(rnamespaces, "");
+
+ jQuery.each( jQuery.data(this, "events").live || [], function() {
+ if ( type === this.origType.replace(rnamespaces, "") ) {
+ remove = false;
+ return false;
+ }
+ });
+
+ if ( remove ) {
+ jQuery.event.remove( this, handleObj.origType, liveHandler );
+ }
+ }
+
+ },
+
+ beforeunload: {
+ setup: function( data, namespaces, eventHandle ) {
+ // We only want to do this special case on windows
+ if ( this.setInterval ) {
+ this.onbeforeunload = eventHandle;
+ }
+
+ return false;
+ },
+ teardown: function( namespaces, eventHandle ) {
+ if ( this.onbeforeunload === eventHandle ) {
+ this.onbeforeunload = null;
+ }
+ }
+ }
+ }
+};
+
+var removeEvent = document.removeEventListener ?
+ function( elem, type, handle ) {
+ elem.removeEventListener( type, handle, false );
+ } :
+ function( elem, type, handle ) {
+ elem.detachEvent( "on" + type, handle );
+ };
+
+jQuery.Event = function( src ) {
+ // Allow instantiation without the 'new' keyword
+ if ( !this.preventDefault ) {
+ return new jQuery.Event( src );
+ }
+
+ // Event object
+ if ( src && src.type ) {
+ this.originalEvent = src;
+ this.type = src.type;
+ // Event type
+ } else {
+ this.type = src;
+ }
+
+ // timeStamp is buggy for some events on Firefox(#3843)
+ // So we won't rely on the native value
+ this.timeStamp = now();
+
+ // Mark it as fixed
+ this[ expando ] = true;
+};
+
+function returnFalse() {
+ return false;
+}
+function returnTrue() {
+ return true;
+}
+
+// jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding
+// http://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html
+jQuery.Event.prototype = {
+ preventDefault: function() {
+ this.isDefaultPrevented = returnTrue;
+
+ var e = this.originalEvent;
+ if ( !e ) {
+ return;
+ }
+
+ // if preventDefault exists run it on the original event
+ if ( e.preventDefault ) {
+ e.preventDefault();
+ }
+ // otherwise set the returnValue property of the original event to false (IE)
+ e.returnValue = false;
+ },
+ stopPropagation: function() {
+ this.isPropagationStopped = returnTrue;
+
+ var e = this.originalEvent;
+ if ( !e ) {
+ return;
+ }
+ // if stopPropagation exists run it on the original event
+ if ( e.stopPropagation ) {
+ e.stopPropagation();
+ }
+ // otherwise set the cancelBubble property of the original event to true (IE)
+ e.cancelBubble = true;
+ },
+ stopImmediatePropagation: function() {
+ this.isImmediatePropagationStopped = returnTrue;
+ this.stopPropagation();
+ },
+ isDefaultPrevented: returnFalse,
+ isPropagationStopped: returnFalse,
+ isImmediatePropagationStopped: returnFalse
+};
+
+// Checks if an event happened on an element within another element
+// Used in jQuery.event.special.mouseenter and mouseleave handlers
+var withinElement = function( event ) {
+ // Check if mouse(over|out) are still within the same parent element
+ var parent = event.relatedTarget;
+
+ // Firefox sometimes assigns relatedTarget a XUL element
+ // which we cannot access the parentNode property of
+ try {
+ // Traverse up the tree
+ while ( parent && parent !== this ) {
+ parent = parent.parentNode;
+ }
+
+ if ( parent !== this ) {
+ // set the correct event type
+ event.type = event.data;
+
+ // handle event if we actually just moused on to a non sub-element
+ jQuery.event.handle.apply( this, arguments );
+ }
+
+ // assuming we've left the element since we most likely mousedover a xul element
+ } catch(e) { }
+},
+
+// In case of event delegation, we only need to rename the event.type,
+// liveHandler will take care of the rest.
+delegate = function( event ) {
+ event.type = event.data;
+ jQuery.event.handle.apply( this, arguments );
+};
+
+// Create mouseenter and mouseleave events
+jQuery.each({
+ mouseenter: "mouseover",
+ mouseleave: "mouseout"
+}, function( orig, fix ) {
+ jQuery.event.special[ orig ] = {
+ setup: function( data ) {
+ jQuery.event.add( this, fix, data && data.selector ? delegate : withinElement, orig );
+ },
+ teardown: function( data ) {
+ jQuery.event.remove( this, fix, data && data.selector ? delegate : withinElement );
+ }
+ };
+});
+
+// submit delegation
+if ( !jQuery.support.submitBubbles ) {
+
+ jQuery.event.special.submit = {
+ setup: function( data, namespaces ) {
+ if ( this.nodeName.toLowerCase() !== "form" ) {
+ jQuery.event.add(this, "click.specialSubmit", function( e ) {
+ var elem = e.target, type = elem.type;
+
+ if ( (type === "submit" || type === "image") && jQuery( elem ).closest("form").length ) {
+ return trigger( "submit", this, arguments );
+ }
+ });
+
+ jQuery.event.add(this, "keypress.specialSubmit", function( e ) {
+ var elem = e.target, type = elem.type;
+
+ if ( (type === "text" || type === "password") && jQuery( elem ).closest("form").length && e.keyCode === 13 ) {
+ return trigger( "submit", this, arguments );
+ }
+ });
+
+ } else {
+ return false;
+ }
+ },
+
+ teardown: function( namespaces ) {
+ jQuery.event.remove( this, ".specialSubmit" );
+ }
+ };
+
+}
+
+// change delegation, happens here so we have bind.
+if ( !jQuery.support.changeBubbles ) {
+
+ var formElems = /textarea|input|select/i,
+
+ changeFilters,
+
+ getVal = function( elem ) {
+ var type = elem.type, val = elem.value;
+
+ if ( type === "radio" || type === "checkbox" ) {
+ val = elem.checked;
+
+ } else if ( type === "select-multiple" ) {
+ val = elem.selectedIndex > -1 ?
+ jQuery.map( elem.options, function( elem ) {
+ return elem.selected;
+ }).join("-") :
+ "";
+
+ } else if ( elem.nodeName.toLowerCase() === "select" ) {
+ val = elem.selectedIndex;
+ }
+
+ return val;
+ },
+
+ testChange = function testChange( e ) {
+ var elem = e.target, data, val;
+
+ if ( !formElems.test( elem.nodeName ) || elem.readOnly ) {
+ return;
+ }
+
+ data = jQuery.data( elem, "_change_data" );
+ val = getVal(elem);
+
+ // the current data will be also retrieved by beforeactivate
+ if ( e.type !== "focusout" || elem.type !== "radio" ) {
+ jQuery.data( elem, "_change_data", val );
+ }
+
+ if ( data === undefined || val === data ) {
+ return;
+ }
+
+ if ( data != null || val ) {
+ e.type = "change";
+ return jQuery.event.trigger( e, arguments[1], elem );
+ }
+ };
+
+ jQuery.event.special.change = {
+ filters: {
+ focusout: testChange,
+
+ click: function( e ) {
+ var elem = e.target, type = elem.type;
+
+ if ( type === "radio" || type === "checkbox" || elem.nodeName.toLowerCase() === "select" ) {
+ return testChange.call( this, e );
+ }
+ },
+
+ // Change has to be called before submit
+ // Keydown will be called before keypress, which is used in submit-event delegation
+ keydown: function( e ) {
+ var elem = e.target, type = elem.type;
+
+ if ( (e.keyCode === 13 && elem.nodeName.toLowerCase() !== "textarea") ||
+ (e.keyCode === 32 && (type === "checkbox" || type === "radio")) ||
+ type === "select-multiple" ) {
+ return testChange.call( this, e );
+ }
+ },
+
+ // Beforeactivate happens also before the previous element is blurred
+ // with this event you can't trigger a change event, but you can store
+ // information/focus[in] is not needed anymore
+ beforeactivate: function( e ) {
+ var elem = e.target;
+ jQuery.data( elem, "_change_data", getVal(elem) );
+ }
+ },
+
+ setup: function( data, namespaces ) {
+ if ( this.type === "file" ) {
+ return false;
+ }
+
+ for ( var type in changeFilters ) {
+ jQuery.event.add( this, type + ".specialChange", changeFilters[type] );
+ }
+
+ return formElems.test( this.nodeName );
+ },
+
+ teardown: function( namespaces ) {
+ jQuery.event.remove( this, ".specialChange" );
+
+ return formElems.test( this.nodeName );
+ }
+ };
+
+ changeFilters = jQuery.event.special.change.filters;
+}
+
+function trigger( type, elem, args ) {
+ args[0].type = type;
+ return jQuery.event.handle.apply( elem, args );
+}
+
+// Create "bubbling" focus and blur events
+if ( document.addEventListener ) {
+ jQuery.each({ focus: "focusin", blur: "focusout" }, function( orig, fix ) {
+ jQuery.event.special[ fix ] = {
+ setup: function() {
+ this.addEventListener( orig, handler, true );
+ },
+ teardown: function() {
+ this.removeEventListener( orig, handler, true );
+ }
+ };
+
+ function handler( e ) {
+ e = jQuery.event.fix( e );
+ e.type = fix;
+ return jQuery.event.handle.call( this, e );
+ }
+ });
+}
+
+jQuery.each(["bind", "one"], function( i, name ) {
+ jQuery.fn[ name ] = function( type, data, fn ) {
+ // Handle object literals
+ if ( typeof type === "object" ) {
+ for ( var key in type ) {
+ this[ name ](key, data, type[key], fn);
+ }
+ return this;
+ }
+
+ if ( jQuery.isFunction( data ) ) {
+ fn = data;
+ data = undefined;
+ }
+
+ var handler = name === "one" ? jQuery.proxy( fn, function( event ) {
+ jQuery( this ).unbind( event, handler );
+ return fn.apply( this, arguments );
+ }) : fn;
+
+ if ( type === "unload" && name !== "one" ) {
+ this.one( type, data, fn );
+
+ } else {
+ for ( var i = 0, l = this.length; i < l; i++ ) {
+ jQuery.event.add( this[i], type, handler, data );
+ }
+ }
+
+ return this;
+ };
+});
+
+jQuery.fn.extend({
+ unbind: function( type, fn ) {
+ // Handle object literals
+ if ( typeof type === "object" && !type.preventDefault ) {
+ for ( var key in type ) {
+ this.unbind(key, type[key]);
+ }
+
+ } else {
+ for ( var i = 0, l = this.length; i < l; i++ ) {
+ jQuery.event.remove( this[i], type, fn );
+ }
+ }
+
+ return this;
+ },
+
+ delegate: function( selector, types, data, fn ) {
+ return this.live( types, data, fn, selector );
+ },
+
+ undelegate: function( selector, types, fn ) {
+ if ( arguments.length === 0 ) {
+ return this.unbind( "live" );
+
+ } else {
+ return this.die( types, null, fn, selector );
+ }
+ },
+
+ trigger: function( type, data ) {
+ return this.each(function() {
+ jQuery.event.trigger( type, data, this );
+ });
+ },
+
+ triggerHandler: function( type, data ) {
+ if ( this[0] ) {
+ var event = jQuery.Event( type );
+ event.preventDefault();
+ event.stopPropagation();
+ jQuery.event.trigger( event, data, this[0] );
+ return event.result;
+ }
+ },
+
+ toggle: function( fn ) {
+ // Save reference to arguments for access in closure
+ var args = arguments, i = 1;
+
+ // link all the functions, so any of them can unbind this click handler
+ while ( i < args.length ) {
+ jQuery.proxy( fn, args[ i++ ] );
+ }
+
+ return this.click( jQuery.proxy( fn, function( event ) {
+ // Figure out which function to execute
+ var lastToggle = ( jQuery.data( this, "lastToggle" + fn.guid ) || 0 ) % i;
+ jQuery.data( this, "lastToggle" + fn.guid, lastToggle + 1 );
+
+ // Make sure that clicks stop
+ event.preventDefault();
+
+ // and execute the function
+ return args[ lastToggle ].apply( this, arguments ) || false;
+ }));
+ },
+
+ hover: function( fnOver, fnOut ) {
+ return this.mouseenter( fnOver ).mouseleave( fnOut || fnOver );
+ }
+});
+
+var liveMap = {
+ focus: "focusin",
+ blur: "focusout",
+ mouseenter: "mouseover",
+ mouseleave: "mouseout"
+};
+
+jQuery.each(["live", "die"], function( i, name ) {
+ jQuery.fn[ name ] = function( types, data, fn, origSelector /* Internal Use Only */ ) {
+ var type, i = 0, match, namespaces, preType,
+ selector = origSelector || this.selector,
+ context = origSelector ? this : jQuery( this.context );
+
+ if ( jQuery.isFunction( data ) ) {
+ fn = data;
+ data = undefined;
+ }
+
+ types = (types || "").split(" ");
+
+ while ( (type = types[ i++ ]) != null ) {
+ match = rnamespaces.exec( type );
+ namespaces = "";
+
+ if ( match ) {
+ namespaces = match[0];
+ type = type.replace( rnamespaces, "" );
+ }
+
+ if ( type === "hover" ) {
+ types.push( "mouseenter" + namespaces, "mouseleave" + namespaces );
+ continue;
+ }
+
+ preType = type;
+
+ if ( type === "focus" || type === "blur" ) {
+ types.push( liveMap[ type ] + namespaces );
+ type = type + namespaces;
+
+ } else {
+ type = (liveMap[ type ] || type) + namespaces;
+ }
+
+ if ( name === "live" ) {
+ // bind live handler
+ context.each(function(){
+ jQuery.event.add( this, liveConvert( type, selector ),
+ { data: data, selector: selector, handler: fn, origType: type, origHandler: fn, preType: preType } );
+ });
+
+ } else {
+ // unbind live handler
+ context.unbind( liveConvert( type, selector ), fn );
+ }
+ }
+
+ return this;
+ }
+});
+
+function liveHandler( event ) {
+ var stop, elems = [], selectors = [], args = arguments,
+ related, match, handleObj, elem, j, i, l, data,
+ events = jQuery.data( this, "events" );
+
+ // Make sure we avoid non-left-click bubbling in Firefox (#3861)
+ if ( event.liveFired === this || !events || !events.live || event.button && event.type === "click" ) {
+ return;
+ }
+
+ event.liveFired = this;
+
+ var live = events.live.slice(0);
+
+ for ( j = 0; j < live.length; j++ ) {
+ handleObj = live[j];
+
+ if ( handleObj.origType.replace( rnamespaces, "" ) === event.type ) {
+ selectors.push( handleObj.selector );
+
+ } else {
+ live.splice( j--, 1 );
+ }
+ }
+
+ match = jQuery( event.target ).closest( selectors, event.currentTarget );
+
+ for ( i = 0, l = match.length; i < l; i++ ) {
+ for ( j = 0; j < live.length; j++ ) {
+ handleObj = live[j];
+
+ if ( match[i].selector === handleObj.selector ) {
+ elem = match[i].elem;
+ related = null;
+
+ // Those two events require additional checking
+ if ( handleObj.preType === "mouseenter" || handleObj.preType === "mouseleave" ) {
+ related = jQuery( event.relatedTarget ).closest( handleObj.selector )[0];
+ }
+
+ if ( !related || related !== elem ) {
+ elems.push({ elem: elem, handleObj: handleObj });
+ }
+ }
+ }
+ }
+
+ for ( i = 0, l = elems.length; i < l; i++ ) {
+ match = elems[i];
+ event.currentTarget = match.elem;
+ event.data = match.handleObj.data;
+ event.handleObj = match.handleObj;
+
+ if ( match.handleObj.origHandler.apply( match.elem, args ) === false ) {
+ stop = false;
+ break;
+ }
+ }
+
+ return stop;
+}
+
+function liveConvert( type, selector ) {
+ return "live." + (type && type !== "*" ? type + "." : "") + selector.replace(/\./g, "`").replace(/ /g, "&");
+}
+
+jQuery.each( ("blur focus focusin focusout load resize scroll unload click dblclick " +
+ "mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave " +
+ "change select submit keydown keypress keyup error").split(" "), function( i, name ) {
+
+ // Handle event binding
+ jQuery.fn[ name ] = function( fn ) {
+ return fn ? this.bind( name, fn ) : this.trigger( name );
+ };
+
+ if ( jQuery.attrFn ) {
+ jQuery.attrFn[ name ] = true;
+ }
+});
+
+// Prevent memory leaks in IE
+// Window isn't included so as not to unbind existing unload events
+// More info:
+// - http://isaacschlueter.com/2006/10/msie-memory-leaks/
+if ( window.attachEvent && !window.addEventListener ) {
+ window.attachEvent("onunload", function() {
+ for ( var id in jQuery.cache ) {
+ if ( jQuery.cache[ id ].handle ) {
+ // Try/Catch is to handle iframes being unloaded, see #4280
+ try {
+ jQuery.event.remove( jQuery.cache[ id ].handle.elem );
+ } catch(e) {}
+ }
+ }
+ });
+}
+/*!
+ * Sizzle CSS Selector Engine - v1.0
+ * Copyright 2009, The Dojo Foundation
+ * Released under the MIT, BSD, and GPL Licenses.
+ * More information: http://sizzlejs.com/
+ */
+(function(){
+
+var chunker = /((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^[\]]*\]|['"][^'"]*['"]|[^[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g,
+ done = 0,
+ toString = Object.prototype.toString,
+ hasDuplicate = false,
+ baseHasDuplicate = true;
+
+// Here we check if the JavaScript engine is using some sort of
+// optimization where it does not always call our comparision
+// function. If that is the case, discard the hasDuplicate value.
+// Thus far that includes Google Chrome.
+[0, 0].sort(function(){
+ baseHasDuplicate = false;
+ return 0;
+});
+
+var Sizzle = function(selector, context, results, seed) {
+ results = results || [];
+ var origContext = context = context || document;
+
+ if ( context.nodeType !== 1 && context.nodeType !== 9 ) {
+ return [];
+ }
+
+ if ( !selector || typeof selector !== "string" ) {
+ return results;
+ }
+
+ var parts = [], m, set, checkSet, extra, prune = true, contextXML = isXML(context),
+ soFar = selector;
+
+ // Reset the position of the chunker regexp (start from head)
+ while ( (chunker.exec(""), m = chunker.exec(soFar)) !== null ) {
+ soFar = m[3];
+
+ parts.push( m[1] );
+
+ if ( m[2] ) {
+ extra = m[3];
+ break;
+ }
+ }
+
+ if ( parts.length > 1 && origPOS.exec( selector ) ) {
+ if ( parts.length === 2 && Expr.relative[ parts[0] ] ) {
+ set = posProcess( parts[0] + parts[1], context );
+ } else {
+ set = Expr.relative[ parts[0] ] ?
+ [ context ] :
+ Sizzle( parts.shift(), context );
+
+ while ( parts.length ) {
+ selector = parts.shift();
+
+ if ( Expr.relative[ selector ] ) {
+ selector += parts.shift();
+ }
+
+ set = posProcess( selector, set );
+ }
+ }
+ } else {
+ // Take a shortcut and set the context if the root selector is an ID
+ // (but not if it'll be faster if the inner selector is an ID)
+ if ( !seed && parts.length > 1 && context.nodeType === 9 && !contextXML &&
+ Expr.match.ID.test(parts[0]) && !Expr.match.ID.test(parts[parts.length - 1]) ) {
+ var ret = Sizzle.find( parts.shift(), context, contextXML );
+ context = ret.expr ? Sizzle.filter( ret.expr, ret.set )[0] : ret.set[0];
+ }
+
+ if ( context ) {
+ var ret = seed ?
+ { expr: parts.pop(), set: makeArray(seed) } :
+ Sizzle.find( parts.pop(), parts.length === 1 && (parts[0] === "~" || parts[0] === "+") && context.parentNode ? context.parentNode : context, contextXML );
+ set = ret.expr ? Sizzle.filter( ret.expr, ret.set ) : ret.set;
+
+ if ( parts.length > 0 ) {
+ checkSet = makeArray(set);
+ } else {
+ prune = false;
+ }
+
+ while ( parts.length ) {
+ var cur = parts.pop(), pop = cur;
+
+ if ( !Expr.relative[ cur ] ) {
+ cur = "";
+ } else {
+ pop = parts.pop();
+ }
+
+ if ( pop == null ) {
+ pop = context;
+ }
+
+ Expr.relative[ cur ]( checkSet, pop, contextXML );
+ }
+ } else {
+ checkSet = parts = [];
+ }
+ }
+
+ if ( !checkSet ) {
+ checkSet = set;
+ }
+
+ if ( !checkSet ) {
+ Sizzle.error( cur || selector );
+ }
+
+ if ( toString.call(checkSet) === "[object Array]" ) {
+ if ( !prune ) {
+ results.push.apply( results, checkSet );
+ } else if ( context && context.nodeType === 1 ) {
+ for ( var i = 0; checkSet[i] != null; i++ ) {
+ if ( checkSet[i] && (checkSet[i] === true || checkSet[i].nodeType === 1 && contains(context, checkSet[i])) ) {
+ results.push( set[i] );
+ }
+ }
+ } else {
+ for ( var i = 0; checkSet[i] != null; i++ ) {
+ if ( checkSet[i] && checkSet[i].nodeType === 1 ) {
+ results.push( set[i] );
+ }
+ }
+ }
+ } else {
+ makeArray( checkSet, results );
+ }
+
+ if ( extra ) {
+ Sizzle( extra, origContext, results, seed );
+ Sizzle.uniqueSort( results );
+ }
+
+ return results;
+};
+
+Sizzle.uniqueSort = function(results){
+ if ( sortOrder ) {
+ hasDuplicate = baseHasDuplicate;
+ results.sort(sortOrder);
+
+ if ( hasDuplicate ) {
+ for ( var i = 1; i < results.length; i++ ) {
+ if ( results[i] === results[i-1] ) {
+ results.splice(i--, 1);
+ }
+ }
+ }
+ }
+
+ return results;
+};
+
+Sizzle.matches = function(expr, set){
+ return Sizzle(expr, null, null, set);
+};
+
+Sizzle.find = function(expr, context, isXML){
+ var set, match;
+
+ if ( !expr ) {
+ return [];
+ }
+
+ for ( var i = 0, l = Expr.order.length; i < l; i++ ) {
+ var type = Expr.order[i], match;
+
+ if ( (match = Expr.leftMatch[ type ].exec( expr )) ) {
+ var left = match[1];
+ match.splice(1,1);
+
+ if ( left.substr( left.length - 1 ) !== "\\" ) {
+ match[1] = (match[1] || "").replace(/\\/g, "");
+ set = Expr.find[ type ]( match, context, isXML );
+ if ( set != null ) {
+ expr = expr.replace( Expr.match[ type ], "" );
+ break;
+ }
+ }
+ }
+ }
+
+ if ( !set ) {
+ set = context.getElementsByTagName("*");
+ }
+
+ return {set: set, expr: expr};
+};
+
+Sizzle.filter = function(expr, set, inplace, not){
+ var old = expr, result = [], curLoop = set, match, anyFound,
+ isXMLFilter = set && set[0] && isXML(set[0]);
+
+ while ( expr && set.length ) {
+ for ( var type in Expr.filter ) {
+ if ( (match = Expr.leftMatch[ type ].exec( expr )) != null && match[2] ) {
+ var filter = Expr.filter[ type ], found, item, left = match[1];
+ anyFound = false;
+
+ match.splice(1,1);
+
+ if ( left.substr( left.length - 1 ) === "\\" ) {
+ continue;
+ }
+
+ if ( curLoop === result ) {
+ result = [];
+ }
+
+ if ( Expr.preFilter[ type ] ) {
+ match = Expr.preFilter[ type ]( match, curLoop, inplace, result, not, isXMLFilter );
+
+ if ( !match ) {
+ anyFound = found = true;
+ } else if ( match === true ) {
+ continue;
+ }
+ }
+
+ if ( match ) {
+ for ( var i = 0; (item = curLoop[i]) != null; i++ ) {
+ if ( item ) {
+ found = filter( item, match, i, curLoop );
+ var pass = not ^ !!found;
+
+ if ( inplace && found != null ) {
+ if ( pass ) {
+ anyFound = true;
+ } else {
+ curLoop[i] = false;
+ }
+ } else if ( pass ) {
+ result.push( item );
+ anyFound = true;
+ }
+ }
+ }
+ }
+
+ if ( found !== undefined ) {
+ if ( !inplace ) {
+ curLoop = result;
+ }
+
+ expr = expr.replace( Expr.match[ type ], "" );
+
+ if ( !anyFound ) {
+ return [];
+ }
+
+ break;
+ }
+ }
+ }
+
+ // Improper expression
+ if ( expr === old ) {
+ if ( anyFound == null ) {
+ Sizzle.error( expr );
+ } else {
+ break;
+ }
+ }
+
+ old = expr;
+ }
+
+ return curLoop;
+};
+
+Sizzle.error = function( msg ) {
+ throw "Syntax error, unrecognized expression: " + msg;
+};
+
+var Expr = Sizzle.selectors = {
+ order: [ "ID", "NAME", "TAG" ],
+ match: {
+ ID: /#((?:[\w\u00c0-\uFFFF-]|\\.)+)/,
+ CLASS: /\.((?:[\w\u00c0-\uFFFF-]|\\.)+)/,
+ NAME: /\[name=['"]*((?:[\w\u00c0-\uFFFF-]|\\.)+)['"]*\]/,
+ ATTR: /\[\s*((?:[\w\u00c0-\uFFFF-]|\\.)+)\s*(?:(\S?=)\s*(['"]*)(.*?)\3|)\s*\]/,
+ TAG: /^((?:[\w\u00c0-\uFFFF\*-]|\\.)+)/,
+ CHILD: /:(only|nth|last|first)-child(?:\((even|odd|[\dn+-]*)\))?/,
+ POS: /:(nth|eq|gt|lt|first|last|even|odd)(?:\((\d*)\))?(?=[^-]|$)/,
+ PSEUDO: /:((?:[\w\u00c0-\uFFFF-]|\\.)+)(?:\((['"]?)((?:\([^\)]+\)|[^\(\)]*)+)\2\))?/
+ },
+ leftMatch: {},
+ attrMap: {
+ "class": "className",
+ "for": "htmlFor"
+ },
+ attrHandle: {
+ href: function(elem){
+ return elem.getAttribute("href");
+ }
+ },
+ relative: {
+ "+": function(checkSet, part){
+ var isPartStr = typeof part === "string",
+ isTag = isPartStr && !/\W/.test(part),
+ isPartStrNotTag = isPartStr && !isTag;
+
+ if ( isTag ) {
+ part = part.toLowerCase();
+ }
+
+ for ( var i = 0, l = checkSet.length, elem; i < l; i++ ) {
+ if ( (elem = checkSet[i]) ) {
+ while ( (elem = elem.previousSibling) && elem.nodeType !== 1 ) {}
+
+ checkSet[i] = isPartStrNotTag || elem && elem.nodeName.toLowerCase() === part ?
+ elem || false :
+ elem === part;
+ }
+ }
+
+ if ( isPartStrNotTag ) {
+ Sizzle.filter( part, checkSet, true );
+ }
+ },
+ ">": function(checkSet, part){
+ var isPartStr = typeof part === "string";
+
+ if ( isPartStr && !/\W/.test(part) ) {
+ part = part.toLowerCase();
+
+ for ( var i = 0, l = checkSet.length; i < l; i++ ) {
+ var elem = checkSet[i];
+ if ( elem ) {
+ var parent = elem.parentNode;
+ checkSet[i] = parent.nodeName.toLowerCase() === part ? parent : false;
+ }
+ }
+ } else {
+ for ( var i = 0, l = checkSet.length; i < l; i++ ) {
+ var elem = checkSet[i];
+ if ( elem ) {
+ checkSet[i] = isPartStr ?
+ elem.parentNode :
+ elem.parentNode === part;
+ }
+ }
+
+ if ( isPartStr ) {
+ Sizzle.filter( part, checkSet, true );
+ }
+ }
+ },
+ "": function(checkSet, part, isXML){
+ var doneName = done++, checkFn = dirCheck;
+
+ if ( typeof part === "string" && !/\W/.test(part) ) {
+ var nodeCheck = part = part.toLowerCase();
+ checkFn = dirNodeCheck;
+ }
+
+ checkFn("parentNode", part, doneName, checkSet, nodeCheck, isXML);
+ },
+ "~": function(checkSet, part, isXML){
+ var doneName = done++, checkFn = dirCheck;
+
+ if ( typeof part === "string" && !/\W/.test(part) ) {
+ var nodeCheck = part = part.toLowerCase();
+ checkFn = dirNodeCheck;
+ }
+
+ checkFn("previousSibling", part, doneName, checkSet, nodeCheck, isXML);
+ }
+ },
+ find: {
+ ID: function(match, context, isXML){
+ if ( typeof context.getElementById !== "undefined" && !isXML ) {
+ var m = context.getElementById(match[1]);
+ return m ? [m] : [];
+ }
+ },
+ NAME: function(match, context){
+ if ( typeof context.getElementsByName !== "undefined" ) {
+ var ret = [], results = context.getElementsByName(match[1]);
+
+ for ( var i = 0, l = results.length; i < l; i++ ) {
+ if ( results[i].getAttribute("name") === match[1] ) {
+ ret.push( results[i] );
+ }
+ }
+
+ return ret.length === 0 ? null : ret;
+ }
+ },
+ TAG: function(match, context){
+ return context.getElementsByTagName(match[1]);
+ }
+ },
+ preFilter: {
+ CLASS: function(match, curLoop, inplace, result, not, isXML){
+ match = " " + match[1].replace(/\\/g, "") + " ";
+
+ if ( isXML ) {
+ return match;
+ }
+
+ for ( var i = 0, elem; (elem = curLoop[i]) != null; i++ ) {
+ if ( elem ) {
+ if ( not ^ (elem.className && (" " + elem.className + " ").replace(/[\t\n]/g, " ").indexOf(match) >= 0) ) {
+ if ( !inplace ) {
+ result.push( elem );
+ }
+ } else if ( inplace ) {
+ curLoop[i] = false;
+ }
+ }
+ }
+
+ return false;
+ },
+ ID: function(match){
+ return match[1].replace(/\\/g, "");
+ },
+ TAG: function(match, curLoop){
+ return match[1].toLowerCase();
+ },
+ CHILD: function(match){
+ if ( match[1] === "nth" ) {
+ // parse equations like 'even', 'odd', '5', '2n', '3n+2', '4n-1', '-n+6'
+ var test = /(-?)(\d*)n((?:\+|-)?\d*)/.exec(
+ match[2] === "even" && "2n" || match[2] === "odd" && "2n+1" ||
+ !/\D/.test( match[2] ) && "0n+" + match[2] || match[2]);
+
+ // calculate the numbers (first)n+(last) including if they are negative
+ match[2] = (test[1] + (test[2] || 1)) - 0;
+ match[3] = test[3] - 0;
+ }
+
+ // TODO: Move to normal caching system
+ match[0] = done++;
+
+ return match;
+ },
+ ATTR: function(match, curLoop, inplace, result, not, isXML){
+ var name = match[1].replace(/\\/g, "");
+
+ if ( !isXML && Expr.attrMap[name] ) {
+ match[1] = Expr.attrMap[name];
+ }
+
+ if ( match[2] === "~=" ) {
+ match[4] = " " + match[4] + " ";
+ }
+
+ return match;
+ },
+ PSEUDO: function(match, curLoop, inplace, result, not){
+ if ( match[1] === "not" ) {
+ // If we're dealing with a complex expression, or a simple one
+ if ( ( chunker.exec(match[3]) || "" ).length > 1 || /^\w/.test(match[3]) ) {
+ match[3] = Sizzle(match[3], null, null, curLoop);
+ } else {
+ var ret = Sizzle.filter(match[3], curLoop, inplace, true ^ not);
+ if ( !inplace ) {
+ result.push.apply( result, ret );
+ }
+ return false;
+ }
+ } else if ( Expr.match.POS.test( match[0] ) || Expr.match.CHILD.test( match[0] ) ) {
+ return true;
+ }
+
+ return match;
+ },
+ POS: function(match){
+ match.unshift( true );
+ return match;
+ }
+ },
+ filters: {
+ enabled: function(elem){
+ return elem.disabled === false && elem.type !== "hidden";
+ },
+ disabled: function(elem){
+ return elem.disabled === true;
+ },
+ checked: function(elem){
+ return elem.checked === true;
+ },
+ selected: function(elem){
+ // Accessing this property makes selected-by-default
+ // options in Safari work properly
+ elem.parentNode.selectedIndex;
+ return elem.selected === true;
+ },
+ parent: function(elem){
+ return !!elem.firstChild;
+ },
+ empty: function(elem){
+ return !elem.firstChild;
+ },
+ has: function(elem, i, match){
+ return !!Sizzle( match[3], elem ).length;
+ },
+ header: function(elem){
+ return /h\d/i.test( elem.nodeName );
+ },
+ text: function(elem){
+ return "text" === elem.type;
+ },
+ radio: function(elem){
+ return "radio" === elem.type;
+ },
+ checkbox: function(elem){
+ return "checkbox" === elem.type;
+ },
+ file: function(elem){
+ return "file" === elem.type;
+ },
+ password: function(elem){
+ return "password" === elem.type;
+ },
+ submit: function(elem){
+ return "submit" === elem.type;
+ },
+ image: function(elem){
+ return "image" === elem.type;
+ },
+ reset: function(elem){
+ return "reset" === elem.type;
+ },
+ button: function(elem){
+ return "button" === elem.type || elem.nodeName.toLowerCase() === "button";
+ },
+ input: function(elem){
+ return /input|select|textarea|button/i.test(elem.nodeName);
+ }
+ },
+ setFilters: {
+ first: function(elem, i){
+ return i === 0;
+ },
+ last: function(elem, i, match, array){
+ return i === array.length - 1;
+ },
+ even: function(elem, i){
+ return i % 2 === 0;
+ },
+ odd: function(elem, i){
+ return i % 2 === 1;
+ },
+ lt: function(elem, i, match){
+ return i < match[3] - 0;
+ },
+ gt: function(elem, i, match){
+ return i > match[3] - 0;
+ },
+ nth: function(elem, i, match){
+ return match[3] - 0 === i;
+ },
+ eq: function(elem, i, match){
+ return match[3] - 0 === i;
+ }
+ },
+ filter: {
+ PSEUDO: function(elem, match, i, array){
+ var name = match[1], filter = Expr.filters[ name ];
+
+ if ( filter ) {
+ return filter( elem, i, match, array );
+ } else if ( name === "contains" ) {
+ return (elem.textContent || elem.innerText || getText([ elem ]) || "").indexOf(match[3]) >= 0;
+ } else if ( name === "not" ) {
+ var not = match[3];
+
+ for ( var i = 0, l = not.length; i < l; i++ ) {
+ if ( not[i] === elem ) {
+ return false;
+ }
+ }
+
+ return true;
+ } else {
+ Sizzle.error( "Syntax error, unrecognized expression: " + name );
+ }
+ },
+ CHILD: function(elem, match){
+ var type = match[1], node = elem;
+ switch (type) {
+ case 'only':
+ case 'first':
+ while ( (node = node.previousSibling) ) {
+ if ( node.nodeType === 1 ) {
+ return false;
+ }
+ }
+ if ( type === "first" ) {
+ return true;
+ }
+ node = elem;
+ case 'last':
+ while ( (node = node.nextSibling) ) {
+ if ( node.nodeType === 1 ) {
+ return false;
+ }
+ }
+ return true;
+ case 'nth':
+ var first = match[2], last = match[3];
+
+ if ( first === 1 && last === 0 ) {
+ return true;
+ }
+
+ var doneName = match[0],
+ parent = elem.parentNode;
+
+ if ( parent && (parent.sizcache !== doneName || !elem.nodeIndex) ) {
+ var count = 0;
+ for ( node = parent.firstChild; node; node = node.nextSibling ) {
+ if ( node.nodeType === 1 ) {
+ node.nodeIndex = ++count;
+ }
+ }
+ parent.sizcache = doneName;
+ }
+
+ var diff = elem.nodeIndex - last;
+ if ( first === 0 ) {
+ return diff === 0;
+ } else {
+ return ( diff % first === 0 && diff / first >= 0 );
+ }
+ }
+ },
+ ID: function(elem, match){
+ return elem.nodeType === 1 && elem.getAttribute("id") === match;
+ },
+ TAG: function(elem, match){
+ return (match === "*" && elem.nodeType === 1) || elem.nodeName.toLowerCase() === match;
+ },
+ CLASS: function(elem, match){
+ return (" " + (elem.className || elem.getAttribute("class")) + " ")
+ .indexOf( match ) > -1;
+ },
+ ATTR: function(elem, match){
+ var name = match[1],
+ result = Expr.attrHandle[ name ] ?
+ Expr.attrHandle[ name ]( elem ) :
+ elem[ name ] != null ?
+ elem[ name ] :
+ elem.getAttribute( name ),
+ value = result + "",
+ type = match[2],
+ check = match[4];
+
+ return result == null ?
+ type === "!=" :
+ type === "=" ?
+ value === check :
+ type === "*=" ?
+ value.indexOf(check) >= 0 :
+ type === "~=" ?
+ (" " + value + " ").indexOf(check) >= 0 :
+ !check ?
+ value && result !== false :
+ type === "!=" ?
+ value !== check :
+ type === "^=" ?
+ value.indexOf(check) === 0 :
+ type === "$=" ?
+ value.substr(value.length - check.length) === check :
+ type === "|=" ?
+ value === check || value.substr(0, check.length + 1) === check + "-" :
+ false;
+ },
+ POS: function(elem, match, i, array){
+ var name = match[2], filter = Expr.setFilters[ name ];
+
+ if ( filter ) {
+ return filter( elem, i, match, array );
+ }
+ }
+ }
+};
+
+var origPOS = Expr.match.POS;
+
+for ( var type in Expr.match ) {
+ Expr.match[ type ] = new RegExp( Expr.match[ type ].source + /(?![^\[]*\])(?![^\(]*\))/.source );
+ Expr.leftMatch[ type ] = new RegExp( /(^(?:.|\r|\n)*?)/.source + Expr.match[ type ].source.replace(/\\(\d+)/g, function(all, num){
+ return "\\" + (num - 0 + 1);
+ }));
+}
+
+var makeArray = function(array, results) {
+ array = Array.prototype.slice.call( array, 0 );
+
+ if ( results ) {
+ results.push.apply( results, array );
+ return results;
+ }
+
+ return array;
+};
+
+// Perform a simple check to determine if the browser is capable of
+// converting a NodeList to an array using builtin methods.
+// Also verifies that the returned array holds DOM nodes
+// (which is not the case in the Blackberry browser)
+try {
+ Array.prototype.slice.call( document.documentElement.childNodes, 0 )[0].nodeType;
+
+// Provide a fallback method if it does not work
+} catch(e){
+ makeArray = function(array, results) {
+ var ret = results || [];
+
+ if ( toString.call(array) === "[object Array]" ) {
+ Array.prototype.push.apply( ret, array );
+ } else {
+ if ( typeof array.length === "number" ) {
+ for ( var i = 0, l = array.length; i < l; i++ ) {
+ ret.push( array[i] );
+ }
+ } else {
+ for ( var i = 0; array[i]; i++ ) {
+ ret.push( array[i] );
+ }
+ }
+ }
+
+ return ret;
+ };
+}
+
+var sortOrder;
+
+if ( document.documentElement.compareDocumentPosition ) {
+ sortOrder = function( a, b ) {
+ if ( !a.compareDocumentPosition || !b.compareDocumentPosition ) {
+ if ( a == b ) {
+ hasDuplicate = true;
+ }
+ return a.compareDocumentPosition ? -1 : 1;
+ }
+
+ var ret = a.compareDocumentPosition(b) & 4 ? -1 : a === b ? 0 : 1;
+ if ( ret === 0 ) {
+ hasDuplicate = true;
+ }
+ return ret;
+ };
+} else if ( "sourceIndex" in document.documentElement ) {
+ sortOrder = function( a, b ) {
+ if ( !a.sourceIndex || !b.sourceIndex ) {
+ if ( a == b ) {
+ hasDuplicate = true;
+ }
+ return a.sourceIndex ? -1 : 1;
+ }
+
+ var ret = a.sourceIndex - b.sourceIndex;
+ if ( ret === 0 ) {
+ hasDuplicate = true;
+ }
+ return ret;
+ };
+} else if ( document.createRange ) {
+ sortOrder = function( a, b ) {
+ if ( !a.ownerDocument || !b.ownerDocument ) {
+ if ( a == b ) {
+ hasDuplicate = true;
+ }
+ return a.ownerDocument ? -1 : 1;
+ }
+
+ var aRange = a.ownerDocument.createRange(), bRange = b.ownerDocument.createRange();
+ aRange.setStart(a, 0);
+ aRange.setEnd(a, 0);
+ bRange.setStart(b, 0);
+ bRange.setEnd(b, 0);
+ var ret = aRange.compareBoundaryPoints(Range.START_TO_END, bRange);
+ if ( ret === 0 ) {
+ hasDuplicate = true;
+ }
+ return ret;
+ };
+}
+
+// Utility function for retreiving the text value of an array of DOM nodes
+function getText( elems ) {
+ var ret = "", elem;
+
+ for ( var i = 0; elems[i]; i++ ) {
+ elem = elems[i];
+
+ // Get the text from text nodes and CDATA nodes
+ if ( elem.nodeType === 3 || elem.nodeType === 4 ) {
+ ret += elem.nodeValue;
+
+ // Traverse everything else, except comment nodes
+ } else if ( elem.nodeType !== 8 ) {
+ ret += getText( elem.childNodes );
+ }
+ }
+
+ return ret;
+}
+
+// Check to see if the browser returns elements by name when
+// querying by getElementById (and provide a workaround)
+(function(){
+ // We're going to inject a fake input element with a specified name
+ var form = document.createElement("div"),
+ id = "script" + (new Date).getTime();
+ form.innerHTML = "<a name='" + id + "'/>";
+
+ // Inject it into the root element, check its status, and remove it quickly
+ var root = document.documentElement;
+ root.insertBefore( form, root.firstChild );
+
+ // The workaround has to do additional checks after a getElementById
+ // Which slows things down for other browsers (hence the branching)
+ if ( document.getElementById( id ) ) {
+ Expr.find.ID = function(match, context, isXML){
+ if ( typeof context.getElementById !== "undefined" && !isXML ) {
+ var m = context.getElementById(match[1]);
+ return m ? m.id === match[1] || typeof m.getAttributeNode !== "undefined" && m.getAttributeNode("id").nodeValue === match[1] ? [m] : undefined : [];
+ }
+ };
+
+ Expr.filter.ID = function(elem, match){
+ var node = typeof elem.getAttributeNode !== "undefined" && elem.getAttributeNode("id");
+ return elem.nodeType === 1 && node && node.nodeValue === match;
+ };
+ }
+
+ root.removeChild( form );
+ root = form = null; // release memory in IE
+})();
+
+(function(){
+ // Check to see if the browser returns only elements
+ // when doing getElementsByTagName("*")
+
+ // Create a fake element
+ var div = document.createElement("div");
+ div.appendChild( document.createComment("") );
+
+ // Make sure no comments are found
+ if ( div.getElementsByTagName("*").length > 0 ) {
+ Expr.find.TAG = function(match, context){
+ var results = context.getElementsByTagName(match[1]);
+
+ // Filter out possible comments
+ if ( match[1] === "*" ) {
+ var tmp = [];
+
+ for ( var i = 0; results[i]; i++ ) {
+ if ( results[i].nodeType === 1 ) {
+ tmp.push( results[i] );
+ }
+ }
+
+ results = tmp;
+ }
+
+ return results;
+ };
+ }
+
+ // Check to see if an attribute returns normalized href attributes
+ div.innerHTML = "<a href='#'></a>";
+ if ( div.firstChild && typeof div.firstChild.getAttribute !== "undefined" &&
+ div.firstChild.getAttribute("href") !== "#" ) {
+ Expr.attrHandle.href = function(elem){
+ return elem.getAttribute("href", 2);
+ };
+ }
+
+ div = null; // release memory in IE
+})();
+
+if ( document.querySelectorAll ) {
+ (function(){
+ var oldSizzle = Sizzle, div = document.createElement("div");
+ div.innerHTML = "<p class='TEST'></p>";
+
+ // Safari can't handle uppercase or unicode characters when
+ // in quirks mode.
+ if ( div.querySelectorAll && div.querySelectorAll(".TEST").length === 0 ) {
+ return;
+ }
+
+ Sizzle = function(query, context, extra, seed){
+ context = context || document;
+
+ // Only use querySelectorAll on non-XML documents
+ // (ID selectors don't work in non-HTML documents)
+ if ( !seed && context.nodeType === 9 && !isXML(context) ) {
+ try {
+ return makeArray( context.querySelectorAll(query), extra );
+ } catch(e){}
+ }
+
+ return oldSizzle(query, context, extra, seed);
+ };
+
+ for ( var prop in oldSizzle ) {
+ Sizzle[ prop ] = oldSizzle[ prop ];
+ }
+
+ div = null; // release memory in IE
+ })();
+}
+
+(function(){
+ var div = document.createElement("div");
+
+ div.innerHTML = "<div class='test e'></div><div class='test'></div>";
+
+ // Opera can't find a second classname (in 9.6)
+ // Also, make sure that getElementsByClassName actually exists
+ if ( !div.getElementsByClassName || div.getElementsByClassName("e").length === 0 ) {
+ return;
+ }
+
+ // Safari caches class attributes, doesn't catch changes (in 3.2)
+ div.lastChild.className = "e";
+
+ if ( div.getElementsByClassName("e").length === 1 ) {
+ return;
+ }
+
+ Expr.order.splice(1, 0, "CLASS");
+ Expr.find.CLASS = function(match, context, isXML) {
+ if ( typeof context.getElementsByClassName !== "undefined" && !isXML ) {
+ return context.getElementsByClassName(match[1]);
+ }
+ };
+
+ div = null; // release memory in IE
+})();
+
+function dirNodeCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) {
+ for ( var i = 0, l = checkSet.length; i < l; i++ ) {
+ var elem = checkSet[i];
+ if ( elem ) {
+ elem = elem[dir];
+ var match = false;
+
+ while ( elem ) {
+ if ( elem.sizcache === doneName ) {
+ match = checkSet[elem.sizset];
+ break;
+ }
+
+ if ( elem.nodeType === 1 && !isXML ){
+ elem.sizcache = doneName;
+ elem.sizset = i;
+ }
+
+ if ( elem.nodeName.toLowerCase() === cur ) {
+ match = elem;
+ break;
+ }
+
+ elem = elem[dir];
+ }
+
+ checkSet[i] = match;
+ }
+ }
+}
+
+function dirCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) {
+ for ( var i = 0, l = checkSet.length; i < l; i++ ) {
+ var elem = checkSet[i];
+ if ( elem ) {
+ elem = elem[dir];
+ var match = false;
+
+ while ( elem ) {
+ if ( elem.sizcache === doneName ) {
+ match = checkSet[elem.sizset];
+ break;
+ }
+
+ if ( elem.nodeType === 1 ) {
+ if ( !isXML ) {
+ elem.sizcache = doneName;
+ elem.sizset = i;
+ }
+ if ( typeof cur !== "string" ) {
+ if ( elem === cur ) {
+ match = true;
+ break;
+ }
+
+ } else if ( Sizzle.filter( cur, [elem] ).length > 0 ) {
+ match = elem;
+ break;
+ }
+ }
+
+ elem = elem[dir];
+ }
+
+ checkSet[i] = match;
+ }
+ }
+}
+
+var contains = document.compareDocumentPosition ? function(a, b){
+ return !!(a.compareDocumentPosition(b) & 16);
+} : function(a, b){
+ return a !== b && (a.contains ? a.contains(b) : true);
+};
+
+var isXML = function(elem){
+ // documentElement is verified for cases where it doesn't yet exist
+ // (such as loading iframes in IE - #4833)
+ var documentElement = (elem ? elem.ownerDocument || elem : 0).documentElement;
+ return documentElement ? documentElement.nodeName !== "HTML" : false;
+};
+
+var posProcess = function(selector, context){
+ var tmpSet = [], later = "", match,
+ root = context.nodeType ? [context] : context;
+
+ // Position selectors must be done after the filter
+ // And so must :not(positional) so we move all PSEUDOs to the end
+ while ( (match = Expr.match.PSEUDO.exec( selector )) ) {
+ later += match[0];
+ selector = selector.replace( Expr.match.PSEUDO, "" );
+ }
+
+ selector = Expr.relative[selector] ? selector + "*" : selector;
+
+ for ( var i = 0, l = root.length; i < l; i++ ) {
+ Sizzle( selector, root[i], tmpSet );
+ }
+
+ return Sizzle.filter( later, tmpSet );
+};
+
+// EXPOSE
+jQuery.find = Sizzle;
+jQuery.expr = Sizzle.selectors;
+jQuery.expr[":"] = jQuery.expr.filters;
+jQuery.unique = Sizzle.uniqueSort;
+jQuery.text = getText;
+jQuery.isXMLDoc = isXML;
+jQuery.contains = contains;
+
+return;
+
+window.Sizzle = Sizzle;
+
+})();
+var runtil = /Until$/,
+ rparentsprev = /^(?:parents|prevUntil|prevAll)/,
+ // Note: This RegExp should be improved, or likely pulled from Sizzle
+ rmultiselector = /,/,
+ slice = Array.prototype.slice;
+
+// Implement the identical functionality for filter and not
+var winnow = function( elements, qualifier, keep ) {
+ if ( jQuery.isFunction( qualifier ) ) {
+ return jQuery.grep(elements, function( elem, i ) {
+ return !!qualifier.call( elem, i, elem ) === keep;
+ });
+
+ } else if ( qualifier.nodeType ) {
+ return jQuery.grep(elements, function( elem, i ) {
+ return (elem === qualifier) === keep;
+ });
+
+ } else if ( typeof qualifier === "string" ) {
+ var filtered = jQuery.grep(elements, function( elem ) {
+ return elem.nodeType === 1;
+ });
+
+ if ( isSimple.test( qualifier ) ) {
+ return jQuery.filter(qualifier, filtered, !keep);
+ } else {
+ qualifier = jQuery.filter( qualifier, filtered );
+ }
+ }
+
+ return jQuery.grep(elements, function( elem, i ) {
+ return (jQuery.inArray( elem, qualifier ) >= 0) === keep;
+ });
+};
+
+jQuery.fn.extend({
+ find: function( selector ) {
+ var ret = this.pushStack( "", "find", selector ), length = 0;
+
+ for ( var i = 0, l = this.length; i < l; i++ ) {
+ length = ret.length;
+ jQuery.find( selector, this[i], ret );
+
+ if ( i > 0 ) {
+ // Make sure that the results are unique
+ for ( var n = length; n < ret.length; n++ ) {
+ for ( var r = 0; r < length; r++ ) {
+ if ( ret[r] === ret[n] ) {
+ ret.splice(n--, 1);
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ return ret;
+ },
+
+ has: function( target ) {
+ var targets = jQuery( target );
+ return this.filter(function() {
+ for ( var i = 0, l = targets.length; i < l; i++ ) {
+ if ( jQuery.contains( this, targets[i] ) ) {
+ return true;
+ }
+ }
+ });
+ },
+
+ not: function( selector ) {
+ return this.pushStack( winnow(this, selector, false), "not", selector);
+ },
+
+ filter: function( selector ) {
+ return this.pushStack( winnow(this, selector, true), "filter", selector );
+ },
+
+ is: function( selector ) {
+ return !!selector && jQuery.filter( selector, this ).length > 0;
+ },
+
+ closest: function( selectors, context ) {
+ if ( jQuery.isArray( selectors ) ) {
+ var ret = [], cur = this[0], match, matches = {}, selector;
+
+ if ( cur && selectors.length ) {
+ for ( var i = 0, l = selectors.length; i < l; i++ ) {
+ selector = selectors[i];
+
+ if ( !matches[selector] ) {
+ matches[selector] = jQuery.expr.match.POS.test( selector ) ?
+ jQuery( selector, context || this.context ) :
+ selector;
+ }
+ }
+
+ while ( cur && cur.ownerDocument && cur !== context ) {
+ for ( selector in matches ) {
+ match = matches[selector];
+
+ if ( match.jquery ? match.index(cur) > -1 : jQuery(cur).is(match) ) {
+ ret.push({ selector: selector, elem: cur });
+ delete matches[selector];
+ }
+ }
+ cur = cur.parentNode;
+ }
+ }
+
+ return ret;
+ }
+
+ var pos = jQuery.expr.match.POS.test( selectors ) ?
+ jQuery( selectors, context || this.context ) : null;
+
+ return this.map(function( i, cur ) {
+ while ( cur && cur.ownerDocument && cur !== context ) {
+ if ( pos ? pos.index(cur) > -1 : jQuery(cur).is(selectors) ) {
+ return cur;
+ }
+ cur = cur.parentNode;
+ }
+ return null;
+ });
+ },
+
+ // Determine the position of an element within
+ // the matched set of elements
+ index: function( elem ) {
+ if ( !elem || typeof elem === "string" ) {
+ return jQuery.inArray( this[0],
+ // If it receives a string, the selector is used
+ // If it receives nothing, the siblings are used
+ elem ? jQuery( elem ) : this.parent().children() );
+ }
+ // Locate the position of the desired element
+ return jQuery.inArray(
+ // If it receives a jQuery object, the first element is used
+ elem.jquery ? elem[0] : elem, this );
+ },
+
+ add: function( selector, context ) {
+ var set = typeof selector === "string" ?
+ jQuery( selector, context || this.context ) :
+ jQuery.makeArray( selector ),
+ all = jQuery.merge( this.get(), set );
+
+ return this.pushStack( isDisconnected( set[0] ) || isDisconnected( all[0] ) ?
+ all :
+ jQuery.unique( all ) );
+ },
+
+ andSelf: function() {
+ return this.add( this.prevObject );
+ }
+});
+
+// A painfully simple check to see if an element is disconnected
+// from a document (should be improved, where feasible).
+function isDisconnected( node ) {
+ return !node || !node.parentNode || node.parentNode.nodeType === 11;
+}
+
+jQuery.each({
+ parent: function( elem ) {
+ var parent = elem.parentNode;
+ return parent && parent.nodeType !== 11 ? parent : null;
+ },
+ parents: function( elem ) {
+ return jQuery.dir( elem, "parentNode" );
+ },
+ parentsUntil: function( elem, i, until ) {
+ return jQuery.dir( elem, "parentNode", until );
+ },
+ next: function( elem ) {
+ return jQuery.nth( elem, 2, "nextSibling" );
+ },
+ prev: function( elem ) {
+ return jQuery.nth( elem, 2, "previousSibling" );
+ },
+ nextAll: function( elem ) {
+ return jQuery.dir( elem, "nextSibling" );
+ },
+ prevAll: function( elem ) {
+ return jQuery.dir( elem, "previousSibling" );
+ },
+ nextUntil: function( elem, i, until ) {
+ return jQuery.dir( elem, "nextSibling", until );
+ },
+ prevUntil: function( elem, i, until ) {
+ return jQuery.dir( elem, "previousSibling", until );
+ },
+ siblings: function( elem ) {
+ return jQuery.sibling( elem.parentNode.firstChild, elem );
+ },
+ children: function( elem ) {
+ return jQuery.sibling( elem.firstChild );
+ },
+ contents: function( elem ) {
+ return jQuery.nodeName( elem, "iframe" ) ?
+ elem.contentDocument || elem.contentWindow.document :
+ jQuery.makeArray( elem.childNodes );
+ }
+}, function( name, fn ) {
+ jQuery.fn[ name ] = function( until, selector ) {
+ var ret = jQuery.map( this, fn, until );
+
+ if ( !runtil.test( name ) ) {
+ selector = until;
+ }
+
+ if ( selector && typeof selector === "string" ) {
+ ret = jQuery.filter( selector, ret );
+ }
+
+ ret = this.length > 1 ? jQuery.unique( ret ) : ret;
+
+ if ( (this.length > 1 || rmultiselector.test( selector )) && rparentsprev.test( name ) ) {
+ ret = ret.reverse();
+ }
+
+ return this.pushStack( ret, name, slice.call(arguments).join(",") );
+ };
+});
+
+jQuery.extend({
+ filter: function( expr, elems, not ) {
+ if ( not ) {
+ expr = ":not(" + expr + ")";
+ }
+
+ return jQuery.find.matches(expr, elems);
+ },
+
+ dir: function( elem, dir, until ) {
+ var matched = [], cur = elem[dir];
+ while ( cur && cur.nodeType !== 9 && (until === undefined || cur.nodeType !== 1 || !jQuery( cur ).is( until )) ) {
+ if ( cur.nodeType === 1 ) {
+ matched.push( cur );
+ }
+ cur = cur[dir];
+ }
+ return matched;
+ },
+
+ nth: function( cur, result, dir, elem ) {
+ result = result || 1;
+ var num = 0;
+
+ for ( ; cur; cur = cur[dir] ) {
+ if ( cur.nodeType === 1 && ++num === result ) {
+ break;
+ }
+ }
+
+ return cur;
+ },
+
+ sibling: function( n, elem ) {
+ var r = [];
+
+ for ( ; n; n = n.nextSibling ) {
+ if ( n.nodeType === 1 && n !== elem ) {
+ r.push( n );
+ }
+ }
+
+ return r;
+ }
+});
+var rinlinejQuery = / jQuery\d+="(?:\d+|null)"/g,
+ rleadingWhitespace = /^\s+/,
+ rxhtmlTag = /(<([\w:]+)[^>]*?)\/>/g,
+ rselfClosing = /^(?:area|br|col|embed|hr|img|input|link|meta|param)$/i,
+ rtagName = /<([\w:]+)/,
+ rtbody = /<tbody/i,
+ rhtml = /<|&#?\w+;/,
+ rnocache = /<script|<object|<embed|<option|<style/i,
+ rchecked = /checked\s*(?:[^=]|=\s*.checked.)/i, // checked="checked" or checked (html5)
+ fcloseTag = function( all, front, tag ) {
+ return rselfClosing.test( tag ) ?
+ all :
+ front + "></" + tag + ">";
+ },
+ wrapMap = {
+ option: [ 1, "<select multiple='multiple'>", "</select>" ],
+ legend: [ 1, "<fieldset>", "</fieldset>" ],
+ thead: [ 1, "<table>", "</table>" ],
+ tr: [ 2, "<table><tbody>", "</tbody></table>" ],
+ td: [ 3, "<table><tbody><tr>", "</tr></tbody></table>" ],
+ col: [ 2, "<table><tbody></tbody><colgroup>", "</colgroup></table>" ],
+ area: [ 1, "<map>", "</map>" ],
+ _default: [ 0, "", "" ]
+ };
+
+wrapMap.optgroup = wrapMap.option;
+wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead;
+wrapMap.th = wrapMap.td;
+
+// IE can't serialize <link> and <script> tags normally
+if ( !jQuery.support.htmlSerialize ) {
+ wrapMap._default = [ 1, "div<div>", "</div>" ];
+}
+
+jQuery.fn.extend({
+ text: function( text ) {
+ if ( jQuery.isFunction(text) ) {
+ return this.each(function(i) {
+ var self = jQuery(this);
+ self.text( text.call(this, i, self.text()) );
+ });
+ }
+
+ if ( typeof text !== "object" && text !== undefined ) {
+ return this.empty().append( (this[0] && this[0].ownerDocument || document).createTextNode( text ) );
+ }
+
+ return jQuery.text( this );
+ },
+
+ wrapAll: function( html ) {
+ if ( jQuery.isFunction( html ) ) {
+ return this.each(function(i) {
+ jQuery(this).wrapAll( html.call(this, i) );
+ });
+ }
+
+ if ( this[0] ) {
+ // The elements to wrap the target around
+ var wrap = jQuery( html, this[0].ownerDocument ).eq(0).clone(true);
+
+ if ( this[0].parentNode ) {
+ wrap.insertBefore( this[0] );
+ }
+
+ wrap.map(function() {
+ var elem = this;
+
+ while ( elem.firstChild && elem.firstChild.nodeType === 1 ) {
+ elem = elem.firstChild;
+ }
+
+ return elem;
+ }).append(this);
+ }
+
+ return this;
+ },
+
+ wrapInner: function( html ) {
+ if ( jQuery.isFunction( html ) ) {
+ return this.each(function(i) {
+ jQuery(this).wrapInner( html.call(this, i) );
+ });
+ }
+
+ return this.each(function() {
+ var self = jQuery( this ), contents = self.contents();
+
+ if ( contents.length ) {
+ contents.wrapAll( html );
+
+ } else {
+ self.append( html );
+ }
+ });
+ },
+
+ wrap: function( html ) {
+ return this.each(function() {
+ jQuery( this ).wrapAll( html );
+ });
+ },
+
+ unwrap: function() {
+ return this.parent().each(function() {
+ if ( !jQuery.nodeName( this, "body" ) ) {
+ jQuery( this ).replaceWith( this.childNodes );
+ }
+ }).end();
+ },
+
+ append: function() {
+ return this.domManip(arguments, true, function( elem ) {
+ if ( this.nodeType === 1 ) {
+ this.appendChild( elem );
+ }
+ });
+ },
+
+ prepend: function() {
+ return this.domManip(arguments, true, function( elem ) {
+ if ( this.nodeType === 1 ) {
+ this.insertBefore( elem, this.firstChild );
+ }
+ });
+ },
+
+ before: function() {
+ if ( this[0] && this[0].parentNode ) {
+ return this.domManip(arguments, false, function( elem ) {
+ this.parentNode.insertBefore( elem, this );
+ });
+ } else if ( arguments.length ) {
+ var set = jQuery(arguments[0]);
+ set.push.apply( set, this.toArray() );
+ return this.pushStack( set, "before", arguments );
+ }
+ },
+
+ after: function() {
+ if ( this[0] && this[0].parentNode ) {
+ return this.domManip(arguments, false, function( elem ) {
+ this.parentNode.insertBefore( elem, this.nextSibling );
+ });
+ } else if ( arguments.length ) {
+ var set = this.pushStack( this, "after", arguments );
+ set.push.apply( set, jQuery(arguments[0]).toArray() );
+ return set;
+ }
+ },
+
+ // keepData is for internal use only--do not document
+ remove: function( selector, keepData ) {
+ for ( var i = 0, elem; (elem = this[i]) != null; i++ ) {
+ if ( !selector || jQuery.filter( selector, [ elem ] ).length ) {
+ if ( !keepData && elem.nodeType === 1 ) {
+ jQuery.cleanData( elem.getElementsByTagName("*") );
+ jQuery.cleanData( [ elem ] );
+ }
+
+ if ( elem.parentNode ) {
+ elem.parentNode.removeChild( elem );
+ }
+ }
+ }
+
+ return this;
+ },
+
+ empty: function() {
+ for ( var i = 0, elem; (elem = this[i]) != null; i++ ) {
+ // Remove element nodes and prevent memory leaks
+ if ( elem.nodeType === 1 ) {
+ jQuery.cleanData( elem.getElementsByTagName("*") );
+ }
+
+ // Remove any remaining nodes
+ while ( elem.firstChild ) {
+ elem.removeChild( elem.firstChild );
+ }
+ }
+
+ return this;
+ },
+
+ clone: function( events ) {
+ // Do the clone
+ var ret = this.map(function() {
+ if ( !jQuery.support.noCloneEvent && !jQuery.isXMLDoc(this) ) {
+ // IE copies events bound via attachEvent when
+ // using cloneNode. Calling detachEvent on the
+ // clone will also remove the events from the orignal
+ // In order to get around this, we use innerHTML.
+ // Unfortunately, this means some modifications to
+ // attributes in IE that are actually only stored
+ // as properties will not be copied (such as the
+ // the name attribute on an input).
+ var html = this.outerHTML, ownerDocument = this.ownerDocument;
+ if ( !html ) {
+ var div = ownerDocument.createElement("div");
+ div.appendChild( this.cloneNode(true) );
+ html = div.innerHTML;
+ }
+
+ return jQuery.clean([html.replace(rinlinejQuery, "")
+ // Handle the case in IE 8 where action=/test/> self-closes a tag
+ .replace(/=([^="'>\s]+\/)>/g, '="$1">')
+ .replace(rleadingWhitespace, "")], ownerDocument)[0];
+ } else {
+ return this.cloneNode(true);
+ }
+ });
+
+ // Copy the events from the original to the clone
+ if ( events === true ) {
+ cloneCopyEvent( this, ret );
+ cloneCopyEvent( this.find("*"), ret.find("*") );
+ }
+
+ // Return the cloned set
+ return ret;
+ },
+
+ html: function( value ) {
+ if ( value === undefined ) {
+ return this[0] && this[0].nodeType === 1 ?
+ this[0].innerHTML.replace(rinlinejQuery, "") :
+ null;
+
+ // See if we can take a shortcut and just use innerHTML
+ } else if ( typeof value === "string" && !rnocache.test( value ) &&
+ (jQuery.support.leadingWhitespace || !rleadingWhitespace.test( value )) &&
+ !wrapMap[ (rtagName.exec( value ) || ["", ""])[1].toLowerCase() ] ) {
+
+ value = value.replace(rxhtmlTag, fcloseTag);
+
+ try {
+ for ( var i = 0, l = this.length; i < l; i++ ) {
+ // Remove element nodes and prevent memory leaks
+ if ( this[i].nodeType === 1 ) {
+ jQuery.cleanData( this[i].getElementsByTagName("*") );
+ this[i].innerHTML = value;
+ }
+ }
+
+ // If using innerHTML throws an exception, use the fallback method
+ } catch(e) {
+ this.empty().append( value );
+ }
+
+ } else if ( jQuery.isFunction( value ) ) {
+ this.each(function(i){
+ var self = jQuery(this), old = self.html();
+ self.empty().append(function(){
+ return value.call( this, i, old );
+ });
+ });
+
+ } else {
+ this.empty().append( value );
+ }
+
+ return this;
+ },
+
+ replaceWith: function( value ) {
+ if ( this[0] && this[0].parentNode ) {
+ // Make sure that the elements are removed from the DOM before they are inserted
+ // this can help fix replacing a parent with child elements
+ if ( jQuery.isFunction( value ) ) {
+ return this.each(function(i) {
+ var self = jQuery(this), old = self.html();
+ self.replaceWith( value.call( this, i, old ) );
+ });
+ }
+
+ if ( typeof value !== "string" ) {
+ value = jQuery(value).detach();
+ }
+
+ return this.each(function() {
+ var next = this.nextSibling, parent = this.parentNode;
+
+ jQuery(this).remove();
+
+ if ( next ) {
+ jQuery(next).before( value );
+ } else {
+ jQuery(parent).append( value );
+ }
+ });
+ } else {
+ return this.pushStack( jQuery(jQuery.isFunction(value) ? value() : value), "replaceWith", value );
+ }
+ },
+
+ detach: function( selector ) {
+ return this.remove( selector, true );
+ },
+
+ domManip: function( args, table, callback ) {
+ var results, first, value = args[0], scripts = [], fragment, parent;
+
+ // We can't cloneNode fragments that contain checked, in WebKit
+ if ( !jQuery.support.checkClone && arguments.length === 3 && typeof value === "string" && rchecked.test( value ) ) {
+ return this.each(function() {
+ jQuery(this).domManip( args, table, callback, true );
+ });
+ }
+
+ if ( jQuery.isFunction(value) ) {
+ return this.each(function(i) {
+ var self = jQuery(this);
+ args[0] = value.call(this, i, table ? self.html() : undefined);
+ self.domManip( args, table, callback );
+ });
+ }
+
+ if ( this[0] ) {
+ parent = value && value.parentNode;
+
+ // If we're in a fragment, just use that instead of building a new one
+ if ( jQuery.support.parentNode && parent && parent.nodeType === 11 && parent.childNodes.length === this.length ) {
+ results = { fragment: parent };
+
+ } else {
+ results = buildFragment( args, this, scripts );
+ }
+
+ fragment = results.fragment;
+
+ if ( fragment.childNodes.length === 1 ) {
+ first = fragment = fragment.firstChild;
+ } else {
+ first = fragment.firstChild;
+ }
+
+ if ( first ) {
+ table = table && jQuery.nodeName( first, "tr" );
+
+ for ( var i = 0, l = this.length; i < l; i++ ) {
+ callback.call(
+ table ?
+ root(this[i], first) :
+ this[i],
+ i > 0 || results.cacheable || this.length > 1 ?
+ fragment.cloneNode(true) :
+ fragment
+ );
+ }
+ }
+
+ if ( scripts.length ) {
+ jQuery.each( scripts, evalScript );
+ }
+ }
+
+ return this;
+
+ function root( elem, cur ) {
+ return jQuery.nodeName(elem, "table") ?
+ (elem.getElementsByTagName("tbody")[0] ||
+ elem.appendChild(elem.ownerDocument.createElement("tbody"))) :
+ elem;
+ }
+ }
+});
+
+function cloneCopyEvent(orig, ret) {
+ var i = 0;
+
+ ret.each(function() {
+ if ( this.nodeName !== (orig[i] && orig[i].nodeName) ) {
+ return;
+ }
+
+ var oldData = jQuery.data( orig[i++] ), curData = jQuery.data( this, oldData ), events = oldData && oldData.events;
+
+ if ( events ) {
+ delete curData.handle;
+ curData.events = {};
+
+ for ( var type in events ) {
+ for ( var handler in events[ type ] ) {
+ jQuery.event.add( this, type, events[ type ][ handler ], events[ type ][ handler ].data );
+ }
+ }
+ }
+ });
+}
+
+function buildFragment( args, nodes, scripts ) {
+ var fragment, cacheable, cacheresults,
+ doc = (nodes && nodes[0] ? nodes[0].ownerDocument || nodes[0] : document);
+
+ // Only cache "small" (1/2 KB) strings that are associated with the main document
+ // Cloning options loses the selected state, so don't cache them
+ // IE 6 doesn't like it when you put <object> or <embed> elements in a fragment
+ // Also, WebKit does not clone 'checked' attributes on cloneNode, so don't cache
+ if ( args.length === 1 && typeof args[0] === "string" && args[0].length < 512 && doc === document &&
+ !rnocache.test( args[0] ) && (jQuery.support.checkClone || !rchecked.test( args[0] )) ) {
+
+ cacheable = true;
+ cacheresults = jQuery.fragments[ args[0] ];
+ if ( cacheresults ) {
+ if ( cacheresults !== 1 ) {
+ fragment = cacheresults;
+ }
+ }
+ }
+
+ if ( !fragment ) {
+ fragment = doc.createDocumentFragment();
+ jQuery.clean( args, doc, fragment, scripts );
+ }
+
+ if ( cacheable ) {
+ jQuery.fragments[ args[0] ] = cacheresults ? fragment : 1;
+ }
+
+ return { fragment: fragment, cacheable: cacheable };
+}
+
+jQuery.fragments = {};
+
+jQuery.each({
+ appendTo: "append",
+ prependTo: "prepend",
+ insertBefore: "before",
+ insertAfter: "after",
+ replaceAll: "replaceWith"
+}, function( name, original ) {
+ jQuery.fn[ name ] = function( selector ) {
+ var ret = [], insert = jQuery( selector ),
+ parent = this.length === 1 && this[0].parentNode;
+
+ if ( parent && parent.nodeType === 11 && parent.childNodes.length === 1 && insert.length === 1 ) {
+ insert[ original ]( this[0] );
+ return this;
+
+ } else {
+ for ( var i = 0, l = insert.length; i < l; i++ ) {
+ var elems = (i > 0 ? this.clone(true) : this).get();
+ jQuery.fn[ original ].apply( jQuery(insert[i]), elems );
+ ret = ret.concat( elems );
+ }
+
+ return this.pushStack( ret, name, insert.selector );
+ }
+ };
+});
+
+jQuery.extend({
+ clean: function( elems, context, fragment, scripts ) {
+ context = context || document;
+
+ // !context.createElement fails in IE with an error but returns typeof 'object'
+ if ( typeof context.createElement === "undefined" ) {
+ context = context.ownerDocument || context[0] && context[0].ownerDocument || document;
+ }
+
+ var ret = [];
+
+ for ( var i = 0, elem; (elem = elems[i]) != null; i++ ) {
+ if ( typeof elem === "number" ) {
+ elem += "";
+ }
+
+ if ( !elem ) {
+ continue;
+ }
+
+ // Convert html string into DOM nodes
+ if ( typeof elem === "string" && !rhtml.test( elem ) ) {
+ elem = context.createTextNode( elem );
+
+ } else if ( typeof elem === "string" ) {
+ // Fix "XHTML"-style tags in all browsers
+ elem = elem.replace(rxhtmlTag, fcloseTag);
+
+ // Trim whitespace, otherwise indexOf won't work as expected
+ var tag = (rtagName.exec( elem ) || ["", ""])[1].toLowerCase(),
+ wrap = wrapMap[ tag ] || wrapMap._default,
+ depth = wrap[0],
+ div = context.createElement("div");
+
+ // Go to html and back, then peel off extra wrappers
+ div.innerHTML = wrap[1] + elem + wrap[2];
+
+ // Move to the right depth
+ while ( depth-- ) {
+ div = div.lastChild;
+ }
+
+ // Remove IE's autoinserted <tbody> from table fragments
+ if ( !jQuery.support.tbody ) {
+
+ // String was a <table>, *may* have spurious <tbody>
+ var hasBody = rtbody.test(elem),
+ tbody = tag === "table" && !hasBody ?
+ div.firstChild && div.firstChild.childNodes :
+
+ // String was a bare <thead> or <tfoot>
+ wrap[1] === "<table>" && !hasBody ?
+ div.childNodes :
+ [];
+
+ for ( var j = tbody.length - 1; j >= 0 ; --j ) {
+ if ( jQuery.nodeName( tbody[ j ], "tbody" ) && !tbody[ j ].childNodes.length ) {
+ tbody[ j ].parentNode.removeChild( tbody[ j ] );
+ }
+ }
+
+ }
+
+ // IE completely kills leading whitespace when innerHTML is used
+ if ( !jQuery.support.leadingWhitespace && rleadingWhitespace.test( elem ) ) {
+ div.insertBefore( context.createTextNode( rleadingWhitespace.exec(elem)[0] ), div.firstChild );
+ }
+
+ elem = div.childNodes;
+ }
+
+ if ( elem.nodeType ) {
+ ret.push( elem );
+ } else {
+ ret = jQuery.merge( ret, elem );
+ }
+ }
+
+ if ( fragment ) {
+ for ( var i = 0; ret[i]; i++ ) {
+ if ( scripts && jQuery.nodeName( ret[i], "script" ) && (!ret[i].type || ret[i].type.toLowerCase() === "text/javascript") ) {
+ scripts.push( ret[i].parentNode ? ret[i].parentNode.removeChild( ret[i] ) : ret[i] );
+
+ } else {
+ if ( ret[i].nodeType === 1 ) {
+ ret.splice.apply( ret, [i + 1, 0].concat(jQuery.makeArray(ret[i].getElementsByTagName("script"))) );
+ }
+ fragment.appendChild( ret[i] );
+ }
+ }
+ }
+
+ return ret;
+ },
+
+ cleanData: function( elems ) {
+ var data, id, cache = jQuery.cache,
+ special = jQuery.event.special,
+ deleteExpando = jQuery.support.deleteExpando;
+
+ for ( var i = 0, elem; (elem = elems[i]) != null; i++ ) {
+ id = elem[ jQuery.expando ];
+
+ if ( id ) {
+ data = cache[ id ];
+
+ if ( data.events ) {
+ for ( var type in data.events ) {
+ if ( special[ type ] ) {
+ jQuery.event.remove( elem, type );
+
+ } else {
+ removeEvent( elem, type, data.handle );
+ }
+ }
+ }
+
+ if ( deleteExpando ) {
+ delete elem[ jQuery.expando ];
+
+ } else if ( elem.removeAttribute ) {
+ elem.removeAttribute( jQuery.expando );
+ }
+
+ delete cache[ id ];
+ }
+ }
+ }
+});
+// exclude the following css properties to add px
+var rexclude = /z-?index|font-?weight|opacity|zoom|line-?height/i,
+ ralpha = /alpha\([^)]*\)/,
+ ropacity = /opacity=([^)]*)/,
+ rfloat = /float/i,
+ rdashAlpha = /-([a-z])/ig,
+ rupper = /([A-Z])/g,
+ rnumpx = /^-?\d+(?:px)?$/i,
+ rnum = /^-?\d/,
+
+ cssShow = { position: "absolute", visibility: "hidden", display:"block" },
+ cssWidth = [ "Left", "Right" ],
+ cssHeight = [ "Top", "Bottom" ],
+
+ // cache check for defaultView.getComputedStyle
+ getComputedStyle = document.defaultView && document.defaultView.getComputedStyle,
+ // normalize float css property
+ styleFloat = jQuery.support.cssFloat ? "cssFloat" : "styleFloat",
+ fcamelCase = function( all, letter ) {
+ return letter.toUpperCase();
+ };
+
+jQuery.fn.css = function( name, value ) {
+ return access( this, name, value, true, function( elem, name, value ) {
+ if ( value === undefined ) {
+ return jQuery.curCSS( elem, name );
+ }
+
+ if ( typeof value === "number" && !rexclude.test(name) ) {
+ value += "px";
+ }
+
+ jQuery.style( elem, name, value );
+ });
+};
+
+jQuery.extend({
+ style: function( elem, name, value ) {
+ // don't set styles on text and comment nodes
+ if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 ) {
+ return undefined;
+ }
+
+ // ignore negative width and height values #1599
+ if ( (name === "width" || name === "height") && parseFloat(value) < 0 ) {
+ value = undefined;
+ }
+
+ var style = elem.style || elem, set = value !== undefined;
+
+ // IE uses filters for opacity
+ if ( !jQuery.support.opacity && name === "opacity" ) {
+ if ( set ) {
+ // IE has trouble with opacity if it does not have layout
+ // Force it by setting the zoom level
+ style.zoom = 1;
+
+ // Set the alpha filter to set the opacity
+ var opacity = parseInt( value, 10 ) + "" === "NaN" ? "" : "alpha(opacity=" + value * 100 + ")";
+ var filter = style.filter || jQuery.curCSS( elem, "filter" ) || "";
+ style.filter = ralpha.test(filter) ? filter.replace(ralpha, opacity) : opacity;
+ }
+
+ return style.filter && style.filter.indexOf("opacity=") >= 0 ?
+ (parseFloat( ropacity.exec(style.filter)[1] ) / 100) + "":
+ "";
+ }
+
+ // Make sure we're using the right name for getting the float value
+ if ( rfloat.test( name ) ) {
+ name = styleFloat;
+ }
+
+ name = name.replace(rdashAlpha, fcamelCase);
+
+ if ( set ) {
+ style[ name ] = value;
+ }
+
+ return style[ name ];
+ },
+
+ css: function( elem, name, force, extra ) {
+ if ( name === "width" || name === "height" ) {
+ var val, props = cssShow, which = name === "width" ? cssWidth : cssHeight;
+
+ function getWH() {
+ val = name === "width" ? elem.offsetWidth : elem.offsetHeight;
+
+ if ( extra === "border" ) {
+ return;
+ }
+
+ jQuery.each( which, function() {
+ if ( !extra ) {
+ val -= parseFloat(jQuery.curCSS( elem, "padding" + this, true)) || 0;
+ }
+
+ if ( extra === "margin" ) {
+ val += parseFloat(jQuery.curCSS( elem, "margin" + this, true)) || 0;
+ } else {
+ val -= parseFloat(jQuery.curCSS( elem, "border" + this + "Width", true)) || 0;
+ }
+ });
+ }
+
+ if ( elem.offsetWidth !== 0 ) {
+ getWH();
+ } else {
+ jQuery.swap( elem, props, getWH );
+ }
+
+ return Math.max(0, Math.round(val));
+ }
+
+ return jQuery.curCSS( elem, name, force );
+ },
+
+ curCSS: function( elem, name, force ) {
+ var ret, style = elem.style, filter;
+
+ // IE uses filters for opacity
+ if ( !jQuery.support.opacity && name === "opacity" && elem.currentStyle ) {
+ ret = ropacity.test(elem.currentStyle.filter || "") ?
+ (parseFloat(RegExp.$1) / 100) + "" :
+ "";
+
+ return ret === "" ?
+ "1" :
+ ret;
+ }
+
+ // Make sure we're using the right name for getting the float value
+ if ( rfloat.test( name ) ) {
+ name = styleFloat;
+ }
+
+ if ( !force && style && style[ name ] ) {
+ ret = style[ name ];
+
+ } else if ( getComputedStyle ) {
+
+ // Only "float" is needed here
+ if ( rfloat.test( name ) ) {
+ name = "float";
+ }
+
+ name = name.replace( rupper, "-$1" ).toLowerCase();
+
+ var defaultView = elem.ownerDocument.defaultView;
+
+ if ( !defaultView ) {
+ return null;
+ }
+
+ var computedStyle = defaultView.getComputedStyle( elem, null );
+
+ if ( computedStyle ) {
+ ret = computedStyle.getPropertyValue( name );
+ }
+
+ // We should always get a number back from opacity
+ if ( name === "opacity" && ret === "" ) {
+ ret = "1";
+ }
+
+ } else if ( elem.currentStyle ) {
+ var camelCase = name.replace(rdashAlpha, fcamelCase);
+
+ ret = elem.currentStyle[ name ] || elem.currentStyle[ camelCase ];
+
+ // From the awesome hack by Dean Edwards
+ // http://erik.eae.net/archives/2007/07/27/18.54.15/#comment-102291
+
+ // If we're not dealing with a regular pixel number
+ // but a number that has a weird ending, we need to convert it to pixels
+ if ( !rnumpx.test( ret ) && rnum.test( ret ) ) {
+ // Remember the original values
+ var left = style.left, rsLeft = elem.runtimeStyle.left;
+
+ // Put in the new values to get a computed value out
+ elem.runtimeStyle.left = elem.currentStyle.left;
+ style.left = camelCase === "fontSize" ? "1em" : (ret || 0);
+ ret = style.pixelLeft + "px";
+
+ // Revert the changed values
+ style.left = left;
+ elem.runtimeStyle.left = rsLeft;
+ }
+ }
+
+ return ret;
+ },
+
+ // A method for quickly swapping in/out CSS properties to get correct calculations
+ swap: function( elem, options, callback ) {
+ var old = {};
+
+ // Remember the old values, and insert the new ones
+ for ( var name in options ) {
+ old[ name ] = elem.style[ name ];
+ elem.style[ name ] = options[ name ];
+ }
+
+ callback.call( elem );
+
+ // Revert the old values
+ for ( var name in options ) {
+ elem.style[ name ] = old[ name ];
+ }
+ }
+});
+
+if ( jQuery.expr && jQuery.expr.filters ) {
+ jQuery.expr.filters.hidden = function( elem ) {
+ var width = elem.offsetWidth, height = elem.offsetHeight,
+ skip = elem.nodeName.toLowerCase() === "tr";
+
+ return width === 0 && height === 0 && !skip ?
+ true :
+ width > 0 && height > 0 && !skip ?
+ false :
+ jQuery.curCSS(elem, "display") === "none";
+ };
+
+ jQuery.expr.filters.visible = function( elem ) {
+ return !jQuery.expr.filters.hidden( elem );
+ };
+}
+var jsc = now(),
+ rscript = /<script(.|\s)*?\/script>/gi,
+ rselectTextarea = /select|textarea/i,
+ rinput = /color|date|datetime|email|hidden|month|number|password|range|search|tel|text|time|url|week/i,
+ jsre = /=\?(&|$)/,
+ rquery = /\?/,
+ rts = /(\?|&)_=.*?(&|$)/,
+ rurl = /^(\w+:)?\/\/([^\/?#]+)/,
+ r20 = /%20/g,
+
+ // Keep a copy of the old load method
+ _load = jQuery.fn.load;
+
+jQuery.fn.extend({
+ load: function( url, params, callback ) {
+ if ( typeof url !== "string" ) {
+ return _load.call( this, url );
+
+ // Don't do a request if no elements are being requested
+ } else if ( !this.length ) {
+ return this;
+ }
+
+ var off = url.indexOf(" ");
+ if ( off >= 0 ) {
+ var selector = url.slice(off, url.length);
+ url = url.slice(0, off);
+ }
+
+ // Default to a GET request
+ var type = "GET";
+
+ // If the second parameter was provided
+ if ( params ) {
+ // If it's a function
+ if ( jQuery.isFunction( params ) ) {
+ // We assume that it's the callback
+ callback = params;
+ params = null;
+
+ // Otherwise, build a param string
+ } else if ( typeof params === "object" ) {
+ params = jQuery.param( params, jQuery.ajaxSettings.traditional );
+ type = "POST";
+ }
+ }
+
+ var self = this;
+
+ // Request the remote document
+ jQuery.ajax({
+ url: url,
+ type: type,
+ dataType: "html",
+ data: params,
+ complete: function( res, status ) {
+ // If successful, inject the HTML into all the matched elements
+ if ( status === "success" || status === "notmodified" ) {
+ // See if a selector was specified
+ self.html( selector ?
+ // Create a dummy div to hold the results
+ jQuery("<div />")
+ // inject the contents of the document in, removing the scripts
+ // to avoid any 'Permission Denied' errors in IE
+ .append(res.responseText.replace(rscript, ""))
+
+ // Locate the specified elements
+ .find(selector) :
+
+ // If not, just inject the full result
+ res.responseText );
+ }
+
+ if ( callback ) {
+ self.each( callback, [res.responseText, status, res] );
+ }
+ }
+ });
+
+ return this;
+ },
+
+ serialize: function() {
+ return jQuery.param(this.serializeArray());
+ },
+ serializeArray: function() {
+ return this.map(function() {
+ return this.elements ? jQuery.makeArray(this.elements) : this;
+ })
+ .filter(function() {
+ return this.name && !this.disabled &&
+ (this.checked || rselectTextarea.test(this.nodeName) ||
+ rinput.test(this.type));
+ })
+ .map(function( i, elem ) {
+ var val = jQuery(this).val();
+
+ return val == null ?
+ null :
+ jQuery.isArray(val) ?
+ jQuery.map( val, function( val, i ) {
+ return { name: elem.name, value: val };
+ }) :
+ { name: elem.name, value: val };
+ }).get();
+ }
+});
+
+// Attach a bunch of functions for handling common AJAX events
+jQuery.each( "ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split(" "), function( i, o ) {
+ jQuery.fn[o] = function( f ) {
+ return this.bind(o, f);
+ };
+});
+
+jQuery.extend({
+
+ get: function( url, data, callback, type ) {
+ // shift arguments if data argument was omited
+ if ( jQuery.isFunction( data ) ) {
+ type = type || callback;
+ callback = data;
+ data = null;
+ }
+
+ return jQuery.ajax({
+ type: "GET",
+ url: url,
+ data: data,
+ success: callback,
+ dataType: type
+ });
+ },
+
+ getScript: function( url, callback ) {
+ return jQuery.get(url, null, callback, "script");
+ },
+
+ getJSON: function( url, data, callback ) {
+ return jQuery.get(url, data, callback, "json");
+ },
+
+ post: function( url, data, callback, type ) {
+ // shift arguments if data argument was omited
+ if ( jQuery.isFunction( data ) ) {
+ type = type || callback;
+ callback = data;
+ data = {};
+ }
+
+ return jQuery.ajax({
+ type: "POST",
+ url: url,
+ data: data,
+ success: callback,
+ dataType: type
+ });
+ },
+
+ ajaxSetup: function( settings ) {
+ jQuery.extend( jQuery.ajaxSettings, settings );
+ },
+
+ ajaxSettings: {
+ url: location.href,
+ global: true,
+ type: "GET",
+ contentType: "application/x-www-form-urlencoded",
+ processData: true,
+ async: true,
+ /*
+ timeout: 0,
+ data: null,
+ username: null,
+ password: null,
+ traditional: false,
+ */
+ // Create the request object; Microsoft failed to properly
+ // implement the XMLHttpRequest in IE7 (can't request local files),
+ // so we use the ActiveXObject when it is available
+ // This function can be overriden by calling jQuery.ajaxSetup
+ xhr: window.XMLHttpRequest && (window.location.protocol !== "file:" || !window.ActiveXObject) ?
+ function() {
+ return new window.XMLHttpRequest();
+ } :
+ function() {
+ try {
+ return new window.ActiveXObject("Microsoft.XMLHTTP");
+ } catch(e) {}
+ },
+ accepts: {
+ xml: "application/xml, text/xml",
+ html: "text/html",
+ script: "text/javascript, application/javascript",
+ json: "application/json, text/javascript",
+ text: "text/plain",
+ _default: "*/*"
+ }
+ },
+
+ // Last-Modified header cache for next request
+ lastModified: {},
+ etag: {},
+
+ ajax: function( origSettings ) {
+ var s = jQuery.extend(true, {}, jQuery.ajaxSettings, origSettings);
+
+ var jsonp, status, data,
+ callbackContext = origSettings && origSettings.context || s,
+ type = s.type.toUpperCase();
+
+ // convert data if not already a string
+ if ( s.data && s.processData && typeof s.data !== "string" ) {
+ s.data = jQuery.param( s.data, s.traditional );
+ }
+
+ // Handle JSONP Parameter Callbacks
+ if ( s.dataType === "jsonp" ) {
+ if ( type === "GET" ) {
+ if ( !jsre.test( s.url ) ) {
+ s.url += (rquery.test( s.url ) ? "&" : "?") + (s.jsonp || "callback") + "=?";
+ }
+ } else if ( !s.data || !jsre.test(s.data) ) {
+ s.data = (s.data ? s.data + "&" : "") + (s.jsonp || "callback") + "=?";
+ }
+ s.dataType = "json";
+ }
+
+ // Build temporary JSONP function
+ if ( s.dataType === "json" && (s.data && jsre.test(s.data) || jsre.test(s.url)) ) {
+ jsonp = s.jsonpCallback || ("jsonp" + jsc++);
+
+ // Replace the =? sequence both in the query string and the data
+ if ( s.data ) {
+ s.data = (s.data + "").replace(jsre, "=" + jsonp + "$1");
+ }
+
+ s.url = s.url.replace(jsre, "=" + jsonp + "$1");
+
+ // We need to make sure
+ // that a JSONP style response is executed properly
+ s.dataType = "script";
+
+ // Handle JSONP-style loading
+ window[ jsonp ] = window[ jsonp ] || function( tmp ) {
+ data = tmp;
+ success();
+ complete();
+ // Garbage collect
+ window[ jsonp ] = undefined;
+
+ try {
+ delete window[ jsonp ];
+ } catch(e) {}
+
+ if ( head ) {
+ head.removeChild( script );
+ }
+ };
+ }
+
+ if ( s.dataType === "script" && s.cache === null ) {
+ s.cache = false;
+ }
+
+ if ( s.cache === false && type === "GET" ) {
+ var ts = now();
+
+ // try replacing _= if it is there
+ var ret = s.url.replace(rts, "$1_=" + ts + "$2");
+
+ // if nothing was replaced, add timestamp to the end
+ s.url = ret + ((ret === s.url) ? (rquery.test(s.url) ? "&" : "?") + "_=" + ts : "");
+ }
+
+ // If data is available, append data to url for get requests
+ if ( s.data && type === "GET" ) {
+ s.url += (rquery.test(s.url) ? "&" : "?") + s.data;
+ }
+
+ // Watch for a new set of requests
+ if ( s.global && ! jQuery.active++ ) {
+ jQuery.event.trigger( "ajaxStart" );
+ }
+
+ // Matches an absolute URL, and saves the domain
+ var parts = rurl.exec( s.url ),
+ remote = parts && (parts[1] && parts[1] !== location.protocol || parts[2] !== location.host);
+
+ // If we're requesting a remote document
+ // and trying to load JSON or Script with a GET
+ if ( s.dataType === "script" && type === "GET" && remote ) {
+ var head = document.getElementsByTagName("head")[0] || document.documentElement;
+ var script = document.createElement("script");
+ script.src = s.url;
+ if ( s.scriptCharset ) {
+ script.charset = s.scriptCharset;
+ }
+
+ // Handle Script loading
+ if ( !jsonp ) {
+ var done = false;
+
+ // Attach handlers for all browsers
+ script.onload = script.onreadystatechange = function() {
+ if ( !done && (!this.readyState ||
+ this.readyState === "loaded" || this.readyState === "complete") ) {
+ done = true;
+ success();
+ complete();
+
+ // Handle memory leak in IE
+ script.onload = script.onreadystatechange = null;
+ if ( head && script.parentNode ) {
+ head.removeChild( script );
+ }
+ }
+ };
+ }
+
+ // Use insertBefore instead of appendChild to circumvent an IE6 bug.
+ // This arises when a base node is used (#2709 and #4378).
+ head.insertBefore( script, head.firstChild );
+
+ // We handle everything using the script element injection
+ return undefined;
+ }
+
+ var requestDone = false;
+
+ // Create the request object
+ var xhr = s.xhr();
+
+ if ( !xhr ) {
+ return;
+ }
+
+ // Open the socket
+ // Passing null username, generates a login popup on Opera (#2865)
+ if ( s.username ) {
+ xhr.open(type, s.url, s.async, s.username, s.password);
+ } else {
+ xhr.open(type, s.url, s.async);
+ }
+
+ // Need an extra try/catch for cross domain requests in Firefox 3
+ try {
+ // Set the correct header, if data is being sent
+ if ( s.data || origSettings && origSettings.contentType ) {
+ xhr.setRequestHeader("Content-Type", s.contentType);
+ }
+
+ // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode.
+ if ( s.ifModified ) {
+ if ( jQuery.lastModified[s.url] ) {
+ xhr.setRequestHeader("If-Modified-Since", jQuery.lastModified[s.url]);
+ }
+
+ if ( jQuery.etag[s.url] ) {
+ xhr.setRequestHeader("If-None-Match", jQuery.etag[s.url]);
+ }
+ }
+
+ // Set header so the called script knows that it's an XMLHttpRequest
+ // Only send the header if it's not a remote XHR
+ if ( !remote ) {
+ xhr.setRequestHeader("X-Requested-With", "XMLHttpRequest");
+ }
+
+ // Set the Accepts header for the server, depending on the dataType
+ xhr.setRequestHeader("Accept", s.dataType && s.accepts[ s.dataType ] ?
+ s.accepts[ s.dataType ] + ", */*" :
+ s.accepts._default );
+ } catch(e) {}
+
+ // Allow custom headers/mimetypes and early abort
+ if ( s.beforeSend && s.beforeSend.call(callbackContext, xhr, s) === false ) {
+ // Handle the global AJAX counter
+ if ( s.global && ! --jQuery.active ) {
+ jQuery.event.trigger( "ajaxStop" );
+ }
+
+ // close opended socket
+ xhr.abort();
+ return false;
+ }
+
+ if ( s.global ) {
+ trigger("ajaxSend", [xhr, s]);
+ }
+
+ // Wait for a response to come back
+ var onreadystatechange = xhr.onreadystatechange = function( isTimeout ) {
+ // The request was aborted
+ if ( !xhr || xhr.readyState === 0 || isTimeout === "abort" ) {
+ // Opera doesn't call onreadystatechange before this point
+ // so we simulate the call
+ if ( !requestDone ) {
+ complete();
+ }
+
+ requestDone = true;
+ if ( xhr ) {
+ xhr.onreadystatechange = jQuery.noop;
+ }
+
+ // The transfer is complete and the data is available, or the request timed out
+ } else if ( !requestDone && xhr && (xhr.readyState === 4 || isTimeout === "timeout") ) {
+ requestDone = true;
+ xhr.onreadystatechange = jQuery.noop;
+
+ status = isTimeout === "timeout" ?
+ "timeout" :
+ !jQuery.httpSuccess( xhr ) ?
+ "error" :
+ s.ifModified && jQuery.httpNotModified( xhr, s.url ) ?
+ "notmodified" :
+ "success";
+
+ var errMsg;
+
+ if ( status === "success" ) {
+ // Watch for, and catch, XML document parse errors
+ try {
+ // process the data (runs the xml through httpData regardless of callback)
+ data = jQuery.httpData( xhr, s.dataType, s );
+ } catch(err) {
+ status = "parsererror";
+ errMsg = err;
+ }
+ }
+
+ // Make sure that the request was successful or notmodified
+ if ( status === "success" || status === "notmodified" ) {
+ // JSONP handles its own success callback
+ if ( !jsonp ) {
+ success();
+ }
+ } else {
+ jQuery.handleError(s, xhr, status, errMsg);
+ }
+
+ // Fire the complete handlers
+ complete();
+
+ if ( isTimeout === "timeout" ) {
+ xhr.abort();
+ }
+
+ // Stop memory leaks
+ if ( s.async ) {
+ xhr = null;
+ }
+ }
+ };
+
+ // Override the abort handler, if we can (IE doesn't allow it, but that's OK)
+ // Opera doesn't fire onreadystatechange at all on abort
+ try {
+ var oldAbort = xhr.abort;
+ xhr.abort = function() {
+ if ( xhr ) {
+ oldAbort.call( xhr );
+ }
+
+ onreadystatechange( "abort" );
+ };
+ } catch(e) { }
+
+ // Timeout checker
+ if ( s.async && s.timeout > 0 ) {
+ setTimeout(function() {
+ // Check to see if the request is still happening
+ if ( xhr && !requestDone ) {
+ onreadystatechange( "timeout" );
+ }
+ }, s.timeout);
+ }
+
+ // Send the data
+ try {
+ xhr.send( type === "POST" || type === "PUT" || type === "DELETE" ? s.data : null );
+ } catch(e) {
+ jQuery.handleError(s, xhr, null, e);
+ // Fire the complete handlers
+ complete();
+ }
+
+ // firefox 1.5 doesn't fire statechange for sync requests
+ if ( !s.async ) {
+ onreadystatechange();
+ }
+
+ function success() {
+ // If a local callback was specified, fire it and pass it the data
+ if ( s.success ) {
+ s.success.call( callbackContext, data, status, xhr );
+ }
+
+ // Fire the global callback
+ if ( s.global ) {
+ trigger( "ajaxSuccess", [xhr, s] );
+ }
+ }
+
+ function complete() {
+ // Process result
+ if ( s.complete ) {
+ s.complete.call( callbackContext, xhr, status);
+ }
+
+ // The request was completed
+ if ( s.global ) {
+ trigger( "ajaxComplete", [xhr, s] );
+ }
+
+ // Handle the global AJAX counter
+ if ( s.global && ! --jQuery.active ) {
+ jQuery.event.trigger( "ajaxStop" );
+ }
+ }
+
+ function trigger(type, args) {
+ (s.context ? jQuery(s.context) : jQuery.event).trigger(type, args);
+ }
+
+ // return XMLHttpRequest to allow aborting the request etc.
+ return xhr;
+ },
+
+ handleError: function( s, xhr, status, e ) {
+ // If a local callback was specified, fire it
+ if ( s.error ) {
+ s.error.call( s.context || s, xhr, status, e );
+ }
+
+ // Fire the global callback
+ if ( s.global ) {
+ (s.context ? jQuery(s.context) : jQuery.event).trigger( "ajaxError", [xhr, s, e] );
+ }
+ },
+
+ // Counter for holding the number of active queries
+ active: 0,
+
+ // Determines if an XMLHttpRequest was successful or not
+ httpSuccess: function( xhr ) {
+ try {
+ // IE error sometimes returns 1223 when it should be 204 so treat it as success, see #1450
+ return !xhr.status && location.protocol === "file:" ||
+ // Opera returns 0 when status is 304
+ ( xhr.status >= 200 && xhr.status < 300 ) ||
+ xhr.status === 304 || xhr.status === 1223 || xhr.status === 0;
+ } catch(e) {}
+
+ return false;
+ },
+
+ // Determines if an XMLHttpRequest returns NotModified
+ httpNotModified: function( xhr, url ) {
+ var lastModified = xhr.getResponseHeader("Last-Modified"),
+ etag = xhr.getResponseHeader("Etag");
+
+ if ( lastModified ) {
+ jQuery.lastModified[url] = lastModified;
+ }
+
+ if ( etag ) {
+ jQuery.etag[url] = etag;
+ }
+
+ // Opera returns 0 when status is 304
+ return xhr.status === 304 || xhr.status === 0;
+ },
+
+ httpData: function( xhr, type, s ) {
+ var ct = xhr.getResponseHeader("content-type") || "",
+ xml = type === "xml" || !type && ct.indexOf("xml") >= 0,
+ data = xml ? xhr.responseXML : xhr.responseText;
+
+ if ( xml && data.documentElement.nodeName === "parsererror" ) {
+ jQuery.error( "parsererror" );
+ }
+
+ // Allow a pre-filtering function to sanitize the response
+ // s is checked to keep backwards compatibility
+ if ( s && s.dataFilter ) {
+ data = s.dataFilter( data, type );
+ }
+
+ // The filter can actually parse the response
+ if ( typeof data === "string" ) {
+ // Get the JavaScript object, if JSON is used.
+ if ( type === "json" || !type && ct.indexOf("json") >= 0 ) {
+ data = jQuery.parseJSON( data );
+
+ // If the type is "script", eval it in global context
+ } else if ( type === "script" || !type && ct.indexOf("javascript") >= 0 ) {
+ jQuery.globalEval( data );
+ }
+ }
+
+ return data;
+ },
+
+ // Serialize an array of form elements or a set of
+ // key/values into a query string
+ param: function( a, traditional ) {
+ var s = [];
+
+ // Set traditional to true for jQuery <= 1.3.2 behavior.
+ if ( traditional === undefined ) {
+ traditional = jQuery.ajaxSettings.traditional;
+ }
+
+ // If an array was passed in, assume that it is an array of form elements.
+ if ( jQuery.isArray(a) || a.jquery ) {
+ // Serialize the form elements
+ jQuery.each( a, function() {
+ add( this.name, this.value );
+ });
+
+ } else {
+ // If traditional, encode the "old" way (the way 1.3.2 or older
+ // did it), otherwise encode params recursively.
+ for ( var prefix in a ) {
+ buildParams( prefix, a[prefix] );
+ }
+ }
+
+ // Return the resulting serialization
+ return s.join("&").replace(r20, "+");
+
+ function buildParams( prefix, obj ) {
+ if ( jQuery.isArray(obj) ) {
+ // Serialize array item.
+ jQuery.each( obj, function( i, v ) {
+ if ( traditional || /\[\]$/.test( prefix ) ) {
+ // Treat each array item as a scalar.
+ add( prefix, v );
+ } else {
+ // If array item is non-scalar (array or object), encode its
+ // numeric index to resolve deserialization ambiguity issues.
+ // Note that rack (as of 1.0.0) can't currently deserialize
+ // nested arrays properly, and attempting to do so may cause
+ // a server error. Possible fixes are to modify rack's
+ // deserialization algorithm or to provide an option or flag
+ // to force array serialization to be shallow.
+ buildParams( prefix + "[" + ( typeof v === "object" || jQuery.isArray(v) ? i : "" ) + "]", v );
+ }
+ });
+
+ } else if ( !traditional && obj != null && typeof obj === "object" ) {
+ // Serialize object item.
+ jQuery.each( obj, function( k, v ) {
+ buildParams( prefix + "[" + k + "]", v );
+ });
+
+ } else {
+ // Serialize scalar item.
+ add( prefix, obj );
+ }
+ }
+
+ function add( key, value ) {
+ // If value is a function, invoke it and return its value
+ value = jQuery.isFunction(value) ? value() : value;
+ s[ s.length ] = encodeURIComponent(key) + "=" + encodeURIComponent(value);
+ }
+ }
+});
+var elemdisplay = {},
+ rfxtypes = /toggle|show|hide/,
+ rfxnum = /^([+-]=)?([\d+-.]+)(.*)$/,
+ timerId,
+ fxAttrs = [
+ // height animations
+ [ "height", "marginTop", "marginBottom", "paddingTop", "paddingBottom" ],
+ // width animations
+ [ "width", "marginLeft", "marginRight", "paddingLeft", "paddingRight" ],
+ // opacity animations
+ [ "opacity" ]
+ ];
+
+jQuery.fn.extend({
+ show: function( speed, callback ) {
+ if ( speed || speed === 0) {
+ return this.animate( genFx("show", 3), speed, callback);
+
+ } else {
+ for ( var i = 0, l = this.length; i < l; i++ ) {
+ var old = jQuery.data(this[i], "olddisplay");
+
+ this[i].style.display = old || "";
+
+ if ( jQuery.css(this[i], "display") === "none" ) {
+ var nodeName = this[i].nodeName, display;
+
+ if ( elemdisplay[ nodeName ] ) {
+ display = elemdisplay[ nodeName ];
+
+ } else {
+ var elem = jQuery("<" + nodeName + " />").appendTo("body");
+
+ display = elem.css("display");
+
+ if ( display === "none" ) {
+ display = "block";
+ }
+
+ elem.remove();
+
+ elemdisplay[ nodeName ] = display;
+ }
+
+ jQuery.data(this[i], "olddisplay", display);
+ }
+ }
+
+ // Set the display of the elements in a second loop
+ // to avoid the constant reflow
+ for ( var j = 0, k = this.length; j < k; j++ ) {
+ this[j].style.display = jQuery.data(this[j], "olddisplay") || "";
+ }
+
+ return this;
+ }
+ },
+
+ hide: function( speed, callback ) {
+ if ( speed || speed === 0 ) {
+ return this.animate( genFx("hide", 3), speed, callback);
+
+ } else {
+ for ( var i = 0, l = this.length; i < l; i++ ) {
+ var old = jQuery.data(this[i], "olddisplay");
+ if ( !old && old !== "none" ) {
+ jQuery.data(this[i], "olddisplay", jQuery.css(this[i], "display"));
+ }
+ }
+
+ // Set the display of the elements in a second loop
+ // to avoid the constant reflow
+ for ( var j = 0, k = this.length; j < k; j++ ) {
+ this[j].style.display = "none";
+ }
+
+ return this;
+ }
+ },
+
+ // Save the old toggle function
+ _toggle: jQuery.fn.toggle,
+
+ toggle: function( fn, fn2 ) {
+ var bool = typeof fn === "boolean";
+
+ if ( jQuery.isFunction(fn) && jQuery.isFunction(fn2) ) {
+ this._toggle.apply( this, arguments );
+
+ } else if ( fn == null || bool ) {
+ this.each(function() {
+ var state = bool ? fn : jQuery(this).is(":hidden");
+ jQuery(this)[ state ? "show" : "hide" ]();
+ });
+
+ } else {
+ this.animate(genFx("toggle", 3), fn, fn2);
+ }
+
+ return this;
+ },
+
+ fadeTo: function( speed, to, callback ) {
+ return this.filter(":hidden").css("opacity", 0).show().end()
+ .animate({opacity: to}, speed, callback);
+ },
+
+ animate: function( prop, speed, easing, callback ) {
+ var optall = jQuery.speed(speed, easing, callback);
+
+ if ( jQuery.isEmptyObject( prop ) ) {
+ return this.each( optall.complete );
+ }
+
+ return this[ optall.queue === false ? "each" : "queue" ](function() {
+ var opt = jQuery.extend({}, optall), p,
+ hidden = this.nodeType === 1 && jQuery(this).is(":hidden"),
+ self = this;
+
+ for ( p in prop ) {
+ var name = p.replace(rdashAlpha, fcamelCase);
+
+ if ( p !== name ) {
+ prop[ name ] = prop[ p ];
+ delete prop[ p ];
+ p = name;
+ }
+
+ if ( prop[p] === "hide" && hidden || prop[p] === "show" && !hidden ) {
+ return opt.complete.call(this);
+ }
+
+ if ( ( p === "height" || p === "width" ) && this.style ) {
+ // Store display property
+ opt.display = jQuery.css(this, "display");
+
+ // Make sure that nothing sneaks out
+ opt.overflow = this.style.overflow;
+ }
+
+ if ( jQuery.isArray( prop[p] ) ) {
+ // Create (if needed) and add to specialEasing
+ (opt.specialEasing = opt.specialEasing || {})[p] = prop[p][1];
+ prop[p] = prop[p][0];
+ }
+ }
+
+ if ( opt.overflow != null ) {
+ this.style.overflow = "hidden";
+ }
+
+ opt.curAnim = jQuery.extend({}, prop);
+
+ jQuery.each( prop, function( name, val ) {
+ var e = new jQuery.fx( self, opt, name );
+
+ if ( rfxtypes.test(val) ) {
+ e[ val === "toggle" ? hidden ? "show" : "hide" : val ]( prop );
+
+ } else {
+ var parts = rfxnum.exec(val),
+ start = e.cur(true) || 0;
+
+ if ( parts ) {
+ var end = parseFloat( parts[2] ),
+ unit = parts[3] || "px";
+
+ // We need to compute starting value
+ if ( unit !== "px" ) {
+ self.style[ name ] = (end || 1) + unit;
+ start = ((end || 1) / e.cur(true)) * start;
+ self.style[ name ] = start + unit;
+ }
+
+ // If a +=/-= token was provided, we're doing a relative animation
+ if ( parts[1] ) {
+ end = ((parts[1] === "-=" ? -1 : 1) * end) + start;
+ }
+
+ e.custom( start, end, unit );
+
+ } else {
+ e.custom( start, val, "" );
+ }
+ }
+ });
+
+ // For JS strict compliance
+ return true;
+ });
+ },
+
+ stop: function( clearQueue, gotoEnd ) {
+ var timers = jQuery.timers;
+
+ if ( clearQueue ) {
+ this.queue([]);
+ }
+
+ this.each(function() {
+ // go in reverse order so anything added to the queue during the loop is ignored
+ for ( var i = timers.length - 1; i >= 0; i-- ) {
+ if ( timers[i].elem === this ) {
+ if (gotoEnd) {
+ // force the next step to be the last
+ timers[i](true);
+ }
+
+ timers.splice(i, 1);
+ }
+ }
+ });
+
+ // start the next in the queue if the last step wasn't forced
+ if ( !gotoEnd ) {
+ this.dequeue();
+ }
+
+ return this;
+ }
+
+});
+
+// Generate shortcuts for custom animations
+jQuery.each({
+ slideDown: genFx("show", 1),
+ slideUp: genFx("hide", 1),
+ slideToggle: genFx("toggle", 1),
+ fadeIn: { opacity: "show" },
+ fadeOut: { opacity: "hide" }
+}, function( name, props ) {
+ jQuery.fn[ name ] = function( speed, callback ) {
+ return this.animate( props, speed, callback );
+ };
+});
+
+jQuery.extend({
+ speed: function( speed, easing, fn ) {
+ var opt = speed && typeof speed === "object" ? speed : {
+ complete: fn || !fn && easing ||
+ jQuery.isFunction( speed ) && speed,
+ duration: speed,
+ easing: fn && easing || easing && !jQuery.isFunction(easing) && easing
+ };
+
+ opt.duration = jQuery.fx.off ? 0 : typeof opt.duration === "number" ? opt.duration :
+ jQuery.fx.speeds[opt.duration] || jQuery.fx.speeds._default;
+
+ // Queueing
+ opt.old = opt.complete;
+ opt.complete = function() {
+ if ( opt.queue !== false ) {
+ jQuery(this).dequeue();
+ }
+ if ( jQuery.isFunction( opt.old ) ) {
+ opt.old.call( this );
+ }
+ };
+
+ return opt;
+ },
+
+ easing: {
+ linear: function( p, n, firstNum, diff ) {
+ return firstNum + diff * p;
+ },
+ swing: function( p, n, firstNum, diff ) {
+ return ((-Math.cos(p*Math.PI)/2) + 0.5) * diff + firstNum;
+ }
+ },
+
+ timers: [],
+
+ fx: function( elem, options, prop ) {
+ this.options = options;
+ this.elem = elem;
+ this.prop = prop;
+
+ if ( !options.orig ) {
+ options.orig = {};
+ }
+ }
+
+});
+
+jQuery.fx.prototype = {
+ // Simple function for setting a style value
+ update: function() {
+ if ( this.options.step ) {
+ this.options.step.call( this.elem, this.now, this );
+ }
+
+ (jQuery.fx.step[this.prop] || jQuery.fx.step._default)( this );
+
+ // Set display property to block for height/width animations
+ if ( ( this.prop === "height" || this.prop === "width" ) && this.elem.style ) {
+ this.elem.style.display = "block";
+ }
+ },
+
+ // Get the current size
+ cur: function( force ) {
+ if ( this.elem[this.prop] != null && (!this.elem.style || this.elem.style[this.prop] == null) ) {
+ return this.elem[ this.prop ];
+ }
+
+ var r = parseFloat(jQuery.css(this.elem, this.prop, force));
+ return r && r > -10000 ? r : parseFloat(jQuery.curCSS(this.elem, this.prop)) || 0;
+ },
+
+ // Start an animation from one number to another
+ custom: function( from, to, unit ) {
+ this.startTime = now();
+ this.start = from;
+ this.end = to;
+ this.unit = unit || this.unit || "px";
+ this.now = this.start;
+ this.pos = this.state = 0;
+
+ var self = this;
+ function t( gotoEnd ) {
+ return self.step(gotoEnd);
+ }
+
+ t.elem = this.elem;
+
+ if ( t() && jQuery.timers.push(t) && !timerId ) {
+ timerId = setInterval(jQuery.fx.tick, 13);
+ }
+ },
+
+ // Simple 'show' function
+ show: function() {
+ // Remember where we started, so that we can go back to it later
+ this.options.orig[this.prop] = jQuery.style( this.elem, this.prop );
+ this.options.show = true;
+
+ // Begin the animation
+ // Make sure that we start at a small width/height to avoid any
+ // flash of content
+ this.custom(this.prop === "width" || this.prop === "height" ? 1 : 0, this.cur());
+
+ // Start by showing the element
+ jQuery( this.elem ).show();
+ },
+
+ // Simple 'hide' function
+ hide: function() {
+ // Remember where we started, so that we can go back to it later
+ this.options.orig[this.prop] = jQuery.style( this.elem, this.prop );
+ this.options.hide = true;
+
+ // Begin the animation
+ this.custom(this.cur(), 0);
+ },
+
+ // Each step of an animation
+ step: function( gotoEnd ) {
+ var t = now(), done = true;
+
+ if ( gotoEnd || t >= this.options.duration + this.startTime ) {
+ this.now = this.end;
+ this.pos = this.state = 1;
+ this.update();
+
+ this.options.curAnim[ this.prop ] = true;
+
+ for ( var i in this.options.curAnim ) {
+ if ( this.options.curAnim[i] !== true ) {
+ done = false;
+ }
+ }
+
+ if ( done ) {
+ if ( this.options.display != null ) {
+ // Reset the overflow
+ this.elem.style.overflow = this.options.overflow;
+
+ // Reset the display
+ var old = jQuery.data(this.elem, "olddisplay");
+ this.elem.style.display = old ? old : this.options.display;
+
+ if ( jQuery.css(this.elem, "display") === "none" ) {
+ this.elem.style.display = "block";
+ }
+ }
+
+ // Hide the element if the "hide" operation was done
+ if ( this.options.hide ) {
+ jQuery(this.elem).hide();
+ }
+
+ // Reset the properties, if the item has been hidden or shown
+ if ( this.options.hide || this.options.show ) {
+ for ( var p in this.options.curAnim ) {
+ jQuery.style(this.elem, p, this.options.orig[p]);
+ }
+ }
+
+ // Execute the complete function
+ this.options.complete.call( this.elem );
+ }
+
+ return false;
+
+ } else {
+ var n = t - this.startTime;
+ this.state = n / this.options.duration;
+
+ // Perform the easing function, defaults to swing
+ var specialEasing = this.options.specialEasing && this.options.specialEasing[this.prop];
+ var defaultEasing = this.options.easing || (jQuery.easing.swing ? "swing" : "linear");
+ this.pos = jQuery.easing[specialEasing || defaultEasing](this.state, n, 0, 1, this.options.duration);
+ this.now = this.start + ((this.end - this.start) * this.pos);
+
+ // Perform the next step of the animation
+ this.update();
+ }
+
+ return true;
+ }
+};
+
+jQuery.extend( jQuery.fx, {
+ tick: function() {
+ var timers = jQuery.timers;
+
+ for ( var i = 0; i < timers.length; i++ ) {
+ if ( !timers[i]() ) {
+ timers.splice(i--, 1);
+ }
+ }
+
+ if ( !timers.length ) {
+ jQuery.fx.stop();
+ }
+ },
+
+ stop: function() {
+ clearInterval( timerId );
+ timerId = null;
+ },
+
+ speeds: {
+ slow: 600,
+ fast: 200,
+ // Default speed
+ _default: 400
+ },
+
+ step: {
+ opacity: function( fx ) {
+ jQuery.style(fx.elem, "opacity", fx.now);
+ },
+
+ _default: function( fx ) {
+ if ( fx.elem.style && fx.elem.style[ fx.prop ] != null ) {
+ fx.elem.style[ fx.prop ] = (fx.prop === "width" || fx.prop === "height" ? Math.max(0, fx.now) : fx.now) + fx.unit;
+ } else {
+ fx.elem[ fx.prop ] = fx.now;
+ }
+ }
+ }
+});
+
+if ( jQuery.expr && jQuery.expr.filters ) {
+ jQuery.expr.filters.animated = function( elem ) {
+ return jQuery.grep(jQuery.timers, function( fn ) {
+ return elem === fn.elem;
+ }).length;
+ };
+}
+
+function genFx( type, num ) {
+ var obj = {};
+
+ jQuery.each( fxAttrs.concat.apply([], fxAttrs.slice(0,num)), function() {
+ obj[ this ] = type;
+ });
+
+ return obj;
+}
+if ( "getBoundingClientRect" in document.documentElement ) {
+ jQuery.fn.offset = function( options ) {
+ var elem = this[0];
+
+ if ( options ) {
+ return this.each(function( i ) {
+ jQuery.offset.setOffset( this, options, i );
+ });
+ }
+
+ if ( !elem || !elem.ownerDocument ) {
+ return null;
+ }
+
+ if ( elem === elem.ownerDocument.body ) {
+ return jQuery.offset.bodyOffset( elem );
+ }
+
+ var box = elem.getBoundingClientRect(), doc = elem.ownerDocument, body = doc.body, docElem = doc.documentElement,
+ clientTop = docElem.clientTop || body.clientTop || 0, clientLeft = docElem.clientLeft || body.clientLeft || 0,
+ top = box.top + (self.pageYOffset || jQuery.support.boxModel && docElem.scrollTop || body.scrollTop ) - clientTop,
+ left = box.left + (self.pageXOffset || jQuery.support.boxModel && docElem.scrollLeft || body.scrollLeft) - clientLeft;
+
+ return { top: top, left: left };
+ };
+
+} else {
+ jQuery.fn.offset = function( options ) {
+ var elem = this[0];
+
+ if ( options ) {
+ return this.each(function( i ) {
+ jQuery.offset.setOffset( this, options, i );
+ });
+ }
+
+ if ( !elem || !elem.ownerDocument ) {
+ return null;
+ }
+
+ if ( elem === elem.ownerDocument.body ) {
+ return jQuery.offset.bodyOffset( elem );
+ }
+
+ jQuery.offset.initialize();
+
+ var offsetParent = elem.offsetParent, prevOffsetParent = elem,
+ doc = elem.ownerDocument, computedStyle, docElem = doc.documentElement,
+ body = doc.body, defaultView = doc.defaultView,
+ prevComputedStyle = defaultView ? defaultView.getComputedStyle( elem, null ) : elem.currentStyle,
+ top = elem.offsetTop, left = elem.offsetLeft;
+
+ while ( (elem = elem.parentNode) && elem !== body && elem !== docElem ) {
+ if ( jQuery.offset.supportsFixedPosition && prevComputedStyle.position === "fixed" ) {
+ break;
+ }
+
+ computedStyle = defaultView ? defaultView.getComputedStyle(elem, null) : elem.currentStyle;
+ top -= elem.scrollTop;
+ left -= elem.scrollLeft;
+
+ if ( elem === offsetParent ) {
+ top += elem.offsetTop;
+ left += elem.offsetLeft;
+
+ if ( jQuery.offset.doesNotAddBorder && !(jQuery.offset.doesAddBorderForTableAndCells && /^t(able|d|h)$/i.test(elem.nodeName)) ) {
+ top += parseFloat( computedStyle.borderTopWidth ) || 0;
+ left += parseFloat( computedStyle.borderLeftWidth ) || 0;
+ }
+
+ prevOffsetParent = offsetParent, offsetParent = elem.offsetParent;
+ }
+
+ if ( jQuery.offset.subtractsBorderForOverflowNotVisible && computedStyle.overflow !== "visible" ) {
+ top += parseFloat( computedStyle.borderTopWidth ) || 0;
+ left += parseFloat( computedStyle.borderLeftWidth ) || 0;
+ }
+
+ prevComputedStyle = computedStyle;
+ }
+
+ if ( prevComputedStyle.position === "relative" || prevComputedStyle.position === "static" ) {
+ top += body.offsetTop;
+ left += body.offsetLeft;
+ }
+
+ if ( jQuery.offset.supportsFixedPosition && prevComputedStyle.position === "fixed" ) {
+ top += Math.max( docElem.scrollTop, body.scrollTop );
+ left += Math.max( docElem.scrollLeft, body.scrollLeft );
+ }
+
+ return { top: top, left: left };
+ };
+}
+
+jQuery.offset = {
+ initialize: function() {
+ var body = document.body, container = document.createElement("div"), innerDiv, checkDiv, table, td, bodyMarginTop = parseFloat( jQuery.curCSS(body, "marginTop", true) ) || 0,
+ html = "<div style='position:absolute;top:0;left:0;margin:0;border:5px solid #000;padding:0;width:1px;height:1px;'><div></div></div><table style='position:absolute;top:0;left:0;margin:0;border:5px solid #000;padding:0;width:1px;height:1px;' cellpadding='0' cellspacing='0'><tr><td></td></tr></table>";
+
+ jQuery.extend( container.style, { position: "absolute", top: 0, left: 0, margin: 0, border: 0, width: "1px", height: "1px", visibility: "hidden" } );
+
+ container.innerHTML = html;
+ body.insertBefore( container, body.firstChild );
+ innerDiv = container.firstChild;
+ checkDiv = innerDiv.firstChild;
+ td = innerDiv.nextSibling.firstChild.firstChild;
+
+ this.doesNotAddBorder = (checkDiv.offsetTop !== 5);
+ this.doesAddBorderForTableAndCells = (td.offsetTop === 5);
+
+ checkDiv.style.position = "fixed", checkDiv.style.top = "20px";
+ // safari subtracts parent border width here which is 5px
+ this.supportsFixedPosition = (checkDiv.offsetTop === 20 || checkDiv.offsetTop === 15);
+ checkDiv.style.position = checkDiv.style.top = "";
+
+ innerDiv.style.overflow = "hidden", innerDiv.style.position = "relative";
+ this.subtractsBorderForOverflowNotVisible = (checkDiv.offsetTop === -5);
+
+ this.doesNotIncludeMarginInBodyOffset = (body.offsetTop !== bodyMarginTop);
+
+ body.removeChild( container );
+ body = container = innerDiv = checkDiv = table = td = null;
+ jQuery.offset.initialize = jQuery.noop;
+ },
+
+ bodyOffset: function( body ) {
+ var top = body.offsetTop, left = body.offsetLeft;
+
+ jQuery.offset.initialize();
+
+ if ( jQuery.offset.doesNotIncludeMarginInBodyOffset ) {
+ top += parseFloat( jQuery.curCSS(body, "marginTop", true) ) || 0;
+ left += parseFloat( jQuery.curCSS(body, "marginLeft", true) ) || 0;
+ }
+
+ return { top: top, left: left };
+ },
+
+ setOffset: function( elem, options, i ) {
+ // set position first, in-case top/left are set even on static elem
+ if ( /static/.test( jQuery.curCSS( elem, "position" ) ) ) {
+ elem.style.position = "relative";
+ }
+ var curElem = jQuery( elem ),
+ curOffset = curElem.offset(),
+ curTop = parseInt( jQuery.curCSS( elem, "top", true ), 10 ) || 0,
+ curLeft = parseInt( jQuery.curCSS( elem, "left", true ), 10 ) || 0;
+
+ if ( jQuery.isFunction( options ) ) {
+ options = options.call( elem, i, curOffset );
+ }
+
+ var props = {
+ top: (options.top - curOffset.top) + curTop,
+ left: (options.left - curOffset.left) + curLeft
+ };
+
+ if ( "using" in options ) {
+ options.using.call( elem, props );
+ } else {
+ curElem.css( props );
+ }
+ }
+};
+
+
+jQuery.fn.extend({
+ position: function() {
+ if ( !this[0] ) {
+ return null;
+ }
+
+ var elem = this[0],
+
+ // Get *real* offsetParent
+ offsetParent = this.offsetParent(),
+
+ // Get correct offsets
+ offset = this.offset(),
+ parentOffset = /^body|html$/i.test(offsetParent[0].nodeName) ? { top: 0, left: 0 } : offsetParent.offset();
+
+ // Subtract element margins
+ // note: when an element has margin: auto the offsetLeft and marginLeft
+ // are the same in Safari causing offset.left to incorrectly be 0
+ offset.top -= parseFloat( jQuery.curCSS(elem, "marginTop", true) ) || 0;
+ offset.left -= parseFloat( jQuery.curCSS(elem, "marginLeft", true) ) || 0;
+
+ // Add offsetParent borders
+ parentOffset.top += parseFloat( jQuery.curCSS(offsetParent[0], "borderTopWidth", true) ) || 0;
+ parentOffset.left += parseFloat( jQuery.curCSS(offsetParent[0], "borderLeftWidth", true) ) || 0;
+
+ // Subtract the two offsets
+ return {
+ top: offset.top - parentOffset.top,
+ left: offset.left - parentOffset.left
+ };
+ },
+
+ offsetParent: function() {
+ return this.map(function() {
+ var offsetParent = this.offsetParent || document.body;
+ while ( offsetParent && (!/^body|html$/i.test(offsetParent.nodeName) && jQuery.css(offsetParent, "position") === "static") ) {
+ offsetParent = offsetParent.offsetParent;
+ }
+ return offsetParent;
+ });
+ }
+});
+
+
+// Create scrollLeft and scrollTop methods
+jQuery.each( ["Left", "Top"], function( i, name ) {
+ var method = "scroll" + name;
+
+ jQuery.fn[ method ] = function(val) {
+ var elem = this[0], win;
+
+ if ( !elem ) {
+ return null;
+ }
+
+ if ( val !== undefined ) {
+ // Set the scroll offset
+ return this.each(function() {
+ win = getWindow( this );
+
+ if ( win ) {
+ win.scrollTo(
+ !i ? val : jQuery(win).scrollLeft(),
+ i ? val : jQuery(win).scrollTop()
+ );
+
+ } else {
+ this[ method ] = val;
+ }
+ });
+ } else {
+ win = getWindow( elem );
+
+ // Return the scroll offset
+ return win ? ("pageXOffset" in win) ? win[ i ? "pageYOffset" : "pageXOffset" ] :
+ jQuery.support.boxModel && win.document.documentElement[ method ] ||
+ win.document.body[ method ] :
+ elem[ method ];
+ }
+ };
+});
+
+function getWindow( elem ) {
+ return ("scrollTo" in elem && elem.document) ?
+ elem :
+ elem.nodeType === 9 ?
+ elem.defaultView || elem.parentWindow :
+ false;
+}
+// Create innerHeight, innerWidth, outerHeight and outerWidth methods
+jQuery.each([ "Height", "Width" ], function( i, name ) {
+
+ var type = name.toLowerCase();
+
+ // innerHeight and innerWidth
+ jQuery.fn["inner" + name] = function() {
+ return this[0] ?
+ jQuery.css( this[0], type, false, "padding" ) :
+ null;
+ };
+
+ // outerHeight and outerWidth
+ jQuery.fn["outer" + name] = function( margin ) {
+ return this[0] ?
+ jQuery.css( this[0], type, false, margin ? "margin" : "border" ) :
+ null;
+ };
+
+ jQuery.fn[ type ] = function( size ) {
+ // Get window width or height
+ var elem = this[0];
+ if ( !elem ) {
+ return size == null ? null : this;
+ }
+
+ if ( jQuery.isFunction( size ) ) {
+ return this.each(function( i ) {
+ var self = jQuery( this );
+ self[ type ]( size.call( this, i, self[ type ]() ) );
+ });
+ }
+
+ return ("scrollTo" in elem && elem.document) ? // does it walk and quack like a window?
+ // Everyone else use document.documentElement or document.body depending on Quirks vs Standards mode
+ elem.document.compatMode === "CSS1Compat" && elem.document.documentElement[ "client" + name ] ||
+ elem.document.body[ "client" + name ] :
+
+ // Get document width or height
+ (elem.nodeType === 9) ? // is it a document
+ // Either scroll[Width/Height] or offset[Width/Height], whichever is greater
+ Math.max(
+ elem.documentElement["client" + name],
+ elem.body["scroll" + name], elem.documentElement["scroll" + name],
+ elem.body["offset" + name], elem.documentElement["offset" + name]
+ ) :
+
+ // Get or set width or height on the element
+ size === undefined ?
+ // Get width or height on the element
+ jQuery.css( elem, type ) :
+
+ // Set the width or height on the element (default to pixels if value is unitless)
+ this.css( type, typeof size === "string" ? size : size + "px" );
+ };
+
+});
+// Expose jQuery to the global object
+window.jQuery = window.$ = jQuery;
+
+})(window);
diff --git a/www/js/jstree-1.0-rc2/jquery-1.4.2.min.js b/www/js/jstree-1.0-rc2/jquery-1.4.2.min.js
new file mode 100644
index 0000000..7c24308
--- /dev/null
+++ b/www/js/jstree-1.0-rc2/jquery-1.4.2.min.js
@@ -0,0 +1,154 @@
+/*!
+ * jQuery JavaScript Library v1.4.2
+ * http://jquery.com/
+ *
+ * Copyright 2010, John Resig
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * Includes Sizzle.js
+ * http://sizzlejs.com/
+ * Copyright 2010, The Dojo Foundation
+ * Released under the MIT, BSD, and GPL Licenses.
+ *
+ * Date: Sat Feb 13 22:33:48 2010 -0500
+ */
+(function(A,w){function ma(){if(!c.isReady){try{s.documentElement.doScroll("left")}catch(a){setTimeout(ma,1);return}c.ready()}}function Qa(a,b){b.src?c.ajax({url:b.src,async:false,dataType:"script"}):c.globalEval(b.text||b.textContent||b.innerHTML||"");b.parentNode&&b.parentNode.removeChild(b)}function X(a,b,d,f,e,j){var i=a.length;if(typeof b==="object"){for(var o in b)X(a,o,b[o],f,e,d);return a}if(d!==w){f=!j&&f&&c.isFunction(d);for(o=0;o<i;o++)e(a[o],b,f?d.call(a[o],o,e(a[o],b)):d,j);return a}return i?
+e(a[0],b):w}function J(){return(new Date).getTime()}function Y(){return false}function Z(){return true}function na(a,b,d){d[0].type=a;return c.event.handle.apply(b,d)}function oa(a){var b,d=[],f=[],e=arguments,j,i,o,k,n,r;i=c.data(this,"events");if(!(a.liveFired===this||!i||!i.live||a.button&&a.type==="click")){a.liveFired=this;var u=i.live.slice(0);for(k=0;k<u.length;k++){i=u[k];i.origType.replace(O,"")===a.type?f.push(i.selector):u.splice(k--,1)}j=c(a.target).closest(f,a.currentTarget);n=0;for(r=
+j.length;n<r;n++)for(k=0;k<u.length;k++){i=u[k];if(j[n].selector===i.selector){o=j[n].elem;f=null;if(i.preType==="mouseenter"||i.preType==="mouseleave")f=c(a.relatedTarget).closest(i.selector)[0];if(!f||f!==o)d.push({elem:o,handleObj:i})}}n=0;for(r=d.length;n<r;n++){j=d[n];a.currentTarget=j.elem;a.data=j.handleObj.data;a.handleObj=j.handleObj;if(j.handleObj.origHandler.apply(j.elem,e)===false){b=false;break}}return b}}function pa(a,b){return"live."+(a&&a!=="*"?a+".":"")+b.replace(/\./g,"`").replace(/ /g,
+"&")}function qa(a){return!a||!a.parentNode||a.parentNode.nodeType===11}function ra(a,b){var d=0;b.each(function(){if(this.nodeName===(a[d]&&a[d].nodeName)){var f=c.data(a[d++]),e=c.data(this,f);if(f=f&&f.events){delete e.handle;e.events={};for(var j in f)for(var i in f[j])c.event.add(this,j,f[j][i],f[j][i].data)}}})}function sa(a,b,d){var f,e,j;b=b&&b[0]?b[0].ownerDocument||b[0]:s;if(a.length===1&&typeof a[0]==="string"&&a[0].length<512&&b===s&&!ta.test(a[0])&&(c.support.checkClone||!ua.test(a[0]))){e=
+true;if(j=c.fragments[a[0]])if(j!==1)f=j}if(!f){f=b.createDocumentFragment();c.clean(a,b,f,d)}if(e)c.fragments[a[0]]=j?f:1;return{fragment:f,cacheable:e}}function K(a,b){var d={};c.each(va.concat.apply([],va.slice(0,b)),function(){d[this]=a});return d}function wa(a){return"scrollTo"in a&&a.document?a:a.nodeType===9?a.defaultView||a.parentWindow:false}var c=function(a,b){return new c.fn.init(a,b)},Ra=A.jQuery,Sa=A.$,s=A.document,T,Ta=/^[^<]*(<[\w\W]+>)[^>]*$|^#([\w-]+)$/,Ua=/^.[^:#\[\.,]*$/,Va=/\S/,
+Wa=/^(\s|\u00A0)+|(\s|\u00A0)+$/g,Xa=/^<(\w+)\s*\/?>(?:<\/\1>)?$/,P=navigator.userAgent,xa=false,Q=[],L,$=Object.prototype.toString,aa=Object.prototype.hasOwnProperty,ba=Array.prototype.push,R=Array.prototype.slice,ya=Array.prototype.indexOf;c.fn=c.prototype={init:function(a,b){var d,f;if(!a)return this;if(a.nodeType){this.context=this[0]=a;this.length=1;return this}if(a==="body"&&!b){this.context=s;this[0]=s.body;this.selector="body";this.length=1;return this}if(typeof a==="string")if((d=Ta.exec(a))&&
+(d[1]||!b))if(d[1]){f=b?b.ownerDocument||b:s;if(a=Xa.exec(a))if(c.isPlainObject(b)){a=[s.createElement(a[1])];c.fn.attr.call(a,b,true)}else a=[f.createElement(a[1])];else{a=sa([d[1]],[f]);a=(a.cacheable?a.fragment.cloneNode(true):a.fragment).childNodes}return c.merge(this,a)}else{if(b=s.getElementById(d[2])){if(b.id!==d[2])return T.find(a);this.length=1;this[0]=b}this.context=s;this.selector=a;return this}else if(!b&&/^\w+$/.test(a)){this.selector=a;this.context=s;a=s.getElementsByTagName(a);return c.merge(this,
+a)}else return!b||b.jquery?(b||T).find(a):c(b).find(a);else if(c.isFunction(a))return T.ready(a);if(a.selector!==w){this.selector=a.selector;this.context=a.context}return c.makeArray(a,this)},selector:"",jquery:"1.4.2",length:0,size:function(){return this.length},toArray:function(){return R.call(this,0)},get:function(a){return a==null?this.toArray():a<0?this.slice(a)[0]:this[a]},pushStack:function(a,b,d){var f=c();c.isArray(a)?ba.apply(f,a):c.merge(f,a);f.prevObject=this;f.context=this.context;if(b===
+"find")f.selector=this.selector+(this.selector?" ":"")+d;else if(b)f.selector=this.selector+"."+b+"("+d+")";return f},each:function(a,b){return c.each(this,a,b)},ready:function(a){c.bindReady();if(c.isReady)a.call(s,c);else Q&&Q.push(a);return this},eq:function(a){return a===-1?this.slice(a):this.slice(a,+a+1)},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},slice:function(){return this.pushStack(R.apply(this,arguments),"slice",R.call(arguments).join(","))},map:function(a){return this.pushStack(c.map(this,
+function(b,d){return a.call(b,d,b)}))},end:function(){return this.prevObject||c(null)},push:ba,sort:[].sort,splice:[].splice};c.fn.init.prototype=c.fn;c.extend=c.fn.extend=function(){var a=arguments[0]||{},b=1,d=arguments.length,f=false,e,j,i,o;if(typeof a==="boolean"){f=a;a=arguments[1]||{};b=2}if(typeof a!=="object"&&!c.isFunction(a))a={};if(d===b){a=this;--b}for(;b<d;b++)if((e=arguments[b])!=null)for(j in e){i=a[j];o=e[j];if(a!==o)if(f&&o&&(c.isPlainObject(o)||c.isArray(o))){i=i&&(c.isPlainObject(i)||
+c.isArray(i))?i:c.isArray(o)?[]:{};a[j]=c.extend(f,i,o)}else if(o!==w)a[j]=o}return a};c.extend({noConflict:function(a){A.$=Sa;if(a)A.jQuery=Ra;return c},isReady:false,ready:function(){if(!c.isReady){if(!s.body)return setTimeout(c.ready,13);c.isReady=true;if(Q){for(var a,b=0;a=Q[b++];)a.call(s,c);Q=null}c.fn.triggerHandler&&c(s).triggerHandler("ready")}},bindReady:function(){if(!xa){xa=true;if(s.readyState==="complete")return c.ready();if(s.addEventListener){s.addEventListener("DOMContentLoaded",
+L,false);A.addEventListener("load",c.ready,false)}else if(s.attachEvent){s.attachEvent("onreadystatechange",L);A.attachEvent("onload",c.ready);var a=false;try{a=A.frameElement==null}catch(b){}s.documentElement.doScroll&&a&&ma()}}},isFunction:function(a){return $.call(a)==="[object Function]"},isArray:function(a){return $.call(a)==="[object Array]"},isPlainObject:function(a){if(!a||$.call(a)!=="[object Object]"||a.nodeType||a.setInterval)return false;if(a.constructor&&!aa.call(a,"constructor")&&!aa.call(a.constructor.prototype,
+"isPrototypeOf"))return false;var b;for(b in a);return b===w||aa.call(a,b)},isEmptyObject:function(a){for(var b in a)return false;return true},error:function(a){throw a;},parseJSON:function(a){if(typeof a!=="string"||!a)return null;a=c.trim(a);if(/^[\],:{}\s]*$/.test(a.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,"@").replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,"]").replace(/(?:^|:|,)(?:\s*\[)+/g,"")))return A.JSON&&A.JSON.parse?A.JSON.parse(a):(new Function("return "+
+a))();else c.error("Invalid JSON: "+a)},noop:function(){},globalEval:function(a){if(a&&Va.test(a)){var b=s.getElementsByTagName("head")[0]||s.documentElement,d=s.createElement("script");d.type="text/javascript";if(c.support.scriptEval)d.appendChild(s.createTextNode(a));else d.text=a;b.insertBefore(d,b.firstChild);b.removeChild(d)}},nodeName:function(a,b){return a.nodeName&&a.nodeName.toUpperCase()===b.toUpperCase()},each:function(a,b,d){var f,e=0,j=a.length,i=j===w||c.isFunction(a);if(d)if(i)for(f in a){if(b.apply(a[f],
+d)===false)break}else for(;e<j;){if(b.apply(a[e++],d)===false)break}else if(i)for(f in a){if(b.call(a[f],f,a[f])===false)break}else for(d=a[0];e<j&&b.call(d,e,d)!==false;d=a[++e]);return a},trim:function(a){return(a||"").replace(Wa,"")},makeArray:function(a,b){b=b||[];if(a!=null)a.length==null||typeof a==="string"||c.isFunction(a)||typeof a!=="function"&&a.setInterval?ba.call(b,a):c.merge(b,a);return b},inArray:function(a,b){if(b.indexOf)return b.indexOf(a);for(var d=0,f=b.length;d<f;d++)if(b[d]===
+a)return d;return-1},merge:function(a,b){var d=a.length,f=0;if(typeof b.length==="number")for(var e=b.length;f<e;f++)a[d++]=b[f];else for(;b[f]!==w;)a[d++]=b[f++];a.length=d;return a},grep:function(a,b,d){for(var f=[],e=0,j=a.length;e<j;e++)!d!==!b(a[e],e)&&f.push(a[e]);return f},map:function(a,b,d){for(var f=[],e,j=0,i=a.length;j<i;j++){e=b(a[j],j,d);if(e!=null)f[f.length]=e}return f.concat.apply([],f)},guid:1,proxy:function(a,b,d){if(arguments.length===2)if(typeof b==="string"){d=a;a=d[b];b=w}else if(b&&
+!c.isFunction(b)){d=b;b=w}if(!b&&a)b=function(){return a.apply(d||this,arguments)};if(a)b.guid=a.guid=a.guid||b.guid||c.guid++;return b},uaMatch:function(a){a=a.toLowerCase();a=/(webkit)[ \/]([\w.]+)/.exec(a)||/(opera)(?:.*version)?[ \/]([\w.]+)/.exec(a)||/(msie) ([\w.]+)/.exec(a)||!/compatible/.test(a)&&/(mozilla)(?:.*? rv:([\w.]+))?/.exec(a)||[];return{browser:a[1]||"",version:a[2]||"0"}},browser:{}});P=c.uaMatch(P);if(P.browser){c.browser[P.browser]=true;c.browser.version=P.version}if(c.browser.webkit)c.browser.safari=
+true;if(ya)c.inArray=function(a,b){return ya.call(b,a)};T=c(s);if(s.addEventListener)L=function(){s.removeEventListener("DOMContentLoaded",L,false);c.ready()};else if(s.attachEvent)L=function(){if(s.readyState==="complete"){s.detachEvent("onreadystatechange",L);c.ready()}};(function(){c.support={};var a=s.documentElement,b=s.createElement("script"),d=s.createElement("div"),f="script"+J();d.style.display="none";d.innerHTML=" <link/><table></table><a href='/a' style='color:red;float:left;opacity:.55;'>a</a><input type='checkbox'/>";
+var e=d.getElementsByTagName("*"),j=d.getElementsByTagName("a")[0];if(!(!e||!e.length||!j)){c.support={leadingWhitespace:d.firstChild.nodeType===3,tbody:!d.getElementsByTagName("tbody").length,htmlSerialize:!!d.getElementsByTagName("link").length,style:/red/.test(j.getAttribute("style")),hrefNormalized:j.getAttribute("href")==="/a",opacity:/^0.55$/.test(j.style.opacity),cssFloat:!!j.style.cssFloat,checkOn:d.getElementsByTagName("input")[0].value==="on",optSelected:s.createElement("select").appendChild(s.createElement("option")).selected,
+parentNode:d.removeChild(d.appendChild(s.createElement("div"))).parentNode===null,deleteExpando:true,checkClone:false,scriptEval:false,noCloneEvent:true,boxModel:null};b.type="text/javascript";try{b.appendChild(s.createTextNode("window."+f+"=1;"))}catch(i){}a.insertBefore(b,a.firstChild);if(A[f]){c.support.scriptEval=true;delete A[f]}try{delete b.test}catch(o){c.support.deleteExpando=false}a.removeChild(b);if(d.attachEvent&&d.fireEvent){d.attachEvent("onclick",function k(){c.support.noCloneEvent=
+false;d.detachEvent("onclick",k)});d.cloneNode(true).fireEvent("onclick")}d=s.createElement("div");d.innerHTML="<input type='radio' name='radiotest' checked='checked'/>";a=s.createDocumentFragment();a.appendChild(d.firstChild);c.support.checkClone=a.cloneNode(true).cloneNode(true).lastChild.checked;c(function(){var k=s.createElement("div");k.style.width=k.style.paddingLeft="1px";s.body.appendChild(k);c.boxModel=c.support.boxModel=k.offsetWidth===2;s.body.removeChild(k).style.display="none"});a=function(k){var n=
+s.createElement("div");k="on"+k;var r=k in n;if(!r){n.setAttribute(k,"return;");r=typeof n[k]==="function"}return r};c.support.submitBubbles=a("submit");c.support.changeBubbles=a("change");a=b=d=e=j=null}})();c.props={"for":"htmlFor","class":"className",readonly:"readOnly",maxlength:"maxLength",cellspacing:"cellSpacing",rowspan:"rowSpan",colspan:"colSpan",tabindex:"tabIndex",usemap:"useMap",frameborder:"frameBorder"};var G="jQuery"+J(),Ya=0,za={};c.extend({cache:{},expando:G,noData:{embed:true,object:true,
+applet:true},data:function(a,b,d){if(!(a.nodeName&&c.noData[a.nodeName.toLowerCase()])){a=a==A?za:a;var f=a[G],e=c.cache;if(!f&&typeof b==="string"&&d===w)return null;f||(f=++Ya);if(typeof b==="object"){a[G]=f;e[f]=c.extend(true,{},b)}else if(!e[f]){a[G]=f;e[f]={}}a=e[f];if(d!==w)a[b]=d;return typeof b==="string"?a[b]:a}},removeData:function(a,b){if(!(a.nodeName&&c.noData[a.nodeName.toLowerCase()])){a=a==A?za:a;var d=a[G],f=c.cache,e=f[d];if(b){if(e){delete e[b];c.isEmptyObject(e)&&c.removeData(a)}}else{if(c.support.deleteExpando)delete a[c.expando];
+else a.removeAttribute&&a.removeAttribute(c.expando);delete f[d]}}}});c.fn.extend({data:function(a,b){if(typeof a==="undefined"&&this.length)return c.data(this[0]);else if(typeof a==="object")return this.each(function(){c.data(this,a)});var d=a.split(".");d[1]=d[1]?"."+d[1]:"";if(b===w){var f=this.triggerHandler("getData"+d[1]+"!",[d[0]]);if(f===w&&this.length)f=c.data(this[0],a);return f===w&&d[1]?this.data(d[0]):f}else return this.trigger("setData"+d[1]+"!",[d[0],b]).each(function(){c.data(this,
+a,b)})},removeData:function(a){return this.each(function(){c.removeData(this,a)})}});c.extend({queue:function(a,b,d){if(a){b=(b||"fx")+"queue";var f=c.data(a,b);if(!d)return f||[];if(!f||c.isArray(d))f=c.data(a,b,c.makeArray(d));else f.push(d);return f}},dequeue:function(a,b){b=b||"fx";var d=c.queue(a,b),f=d.shift();if(f==="inprogress")f=d.shift();if(f){b==="fx"&&d.unshift("inprogress");f.call(a,function(){c.dequeue(a,b)})}}});c.fn.extend({queue:function(a,b){if(typeof a!=="string"){b=a;a="fx"}if(b===
+w)return c.queue(this[0],a);return this.each(function(){var d=c.queue(this,a,b);a==="fx"&&d[0]!=="inprogress"&&c.dequeue(this,a)})},dequeue:function(a){return this.each(function(){c.dequeue(this,a)})},delay:function(a,b){a=c.fx?c.fx.speeds[a]||a:a;b=b||"fx";return this.queue(b,function(){var d=this;setTimeout(function(){c.dequeue(d,b)},a)})},clearQueue:function(a){return this.queue(a||"fx",[])}});var Aa=/[\n\t]/g,ca=/\s+/,Za=/\r/g,$a=/href|src|style/,ab=/(button|input)/i,bb=/(button|input|object|select|textarea)/i,
+cb=/^(a|area)$/i,Ba=/radio|checkbox/;c.fn.extend({attr:function(a,b){return X(this,a,b,true,c.attr)},removeAttr:function(a){return this.each(function(){c.attr(this,a,"");this.nodeType===1&&this.removeAttribute(a)})},addClass:function(a){if(c.isFunction(a))return this.each(function(n){var r=c(this);r.addClass(a.call(this,n,r.attr("class")))});if(a&&typeof a==="string")for(var b=(a||"").split(ca),d=0,f=this.length;d<f;d++){var e=this[d];if(e.nodeType===1)if(e.className){for(var j=" "+e.className+" ",
+i=e.className,o=0,k=b.length;o<k;o++)if(j.indexOf(" "+b[o]+" ")<0)i+=" "+b[o];e.className=c.trim(i)}else e.className=a}return this},removeClass:function(a){if(c.isFunction(a))return this.each(function(k){var n=c(this);n.removeClass(a.call(this,k,n.attr("class")))});if(a&&typeof a==="string"||a===w)for(var b=(a||"").split(ca),d=0,f=this.length;d<f;d++){var e=this[d];if(e.nodeType===1&&e.className)if(a){for(var j=(" "+e.className+" ").replace(Aa," "),i=0,o=b.length;i<o;i++)j=j.replace(" "+b[i]+" ",
+" ");e.className=c.trim(j)}else e.className=""}return this},toggleClass:function(a,b){var d=typeof a,f=typeof b==="boolean";if(c.isFunction(a))return this.each(function(e){var j=c(this);j.toggleClass(a.call(this,e,j.attr("class"),b),b)});return this.each(function(){if(d==="string")for(var e,j=0,i=c(this),o=b,k=a.split(ca);e=k[j++];){o=f?o:!i.hasClass(e);i[o?"addClass":"removeClass"](e)}else if(d==="undefined"||d==="boolean"){this.className&&c.data(this,"__className__",this.className);this.className=
+this.className||a===false?"":c.data(this,"__className__")||""}})},hasClass:function(a){a=" "+a+" ";for(var b=0,d=this.length;b<d;b++)if((" "+this[b].className+" ").replace(Aa," ").indexOf(a)>-1)return true;return false},val:function(a){if(a===w){var b=this[0];if(b){if(c.nodeName(b,"option"))return(b.attributes.value||{}).specified?b.value:b.text;if(c.nodeName(b,"select")){var d=b.selectedIndex,f=[],e=b.options;b=b.type==="select-one";if(d<0)return null;var j=b?d:0;for(d=b?d+1:e.length;j<d;j++){var i=
+e[j];if(i.selected){a=c(i).val();if(b)return a;f.push(a)}}return f}if(Ba.test(b.type)&&!c.support.checkOn)return b.getAttribute("value")===null?"on":b.value;return(b.value||"").replace(Za,"")}return w}var o=c.isFunction(a);return this.each(function(k){var n=c(this),r=a;if(this.nodeType===1){if(o)r=a.call(this,k,n.val());if(typeof r==="number")r+="";if(c.isArray(r)&&Ba.test(this.type))this.checked=c.inArray(n.val(),r)>=0;else if(c.nodeName(this,"select")){var u=c.makeArray(r);c("option",this).each(function(){this.selected=
+c.inArray(c(this).val(),u)>=0});if(!u.length)this.selectedIndex=-1}else this.value=r}})}});c.extend({attrFn:{val:true,css:true,html:true,text:true,data:true,width:true,height:true,offset:true},attr:function(a,b,d,f){if(!a||a.nodeType===3||a.nodeType===8)return w;if(f&&b in c.attrFn)return c(a)[b](d);f=a.nodeType!==1||!c.isXMLDoc(a);var e=d!==w;b=f&&c.props[b]||b;if(a.nodeType===1){var j=$a.test(b);if(b in a&&f&&!j){if(e){b==="type"&&ab.test(a.nodeName)&&a.parentNode&&c.error("type property can't be changed");
+a[b]=d}if(c.nodeName(a,"form")&&a.getAttributeNode(b))return a.getAttributeNode(b).nodeValue;if(b==="tabIndex")return(b=a.getAttributeNode("tabIndex"))&&b.specified?b.value:bb.test(a.nodeName)||cb.test(a.nodeName)&&a.href?0:w;return a[b]}if(!c.support.style&&f&&b==="style"){if(e)a.style.cssText=""+d;return a.style.cssText}e&&a.setAttribute(b,""+d);a=!c.support.hrefNormalized&&f&&j?a.getAttribute(b,2):a.getAttribute(b);return a===null?w:a}return c.style(a,b,d)}});var O=/\.(.*)$/,db=function(a){return a.replace(/[^\w\s\.\|`]/g,
+function(b){return"\\"+b})};c.event={add:function(a,b,d,f){if(!(a.nodeType===3||a.nodeType===8)){if(a.setInterval&&a!==A&&!a.frameElement)a=A;var e,j;if(d.handler){e=d;d=e.handler}if(!d.guid)d.guid=c.guid++;if(j=c.data(a)){var i=j.events=j.events||{},o=j.handle;if(!o)j.handle=o=function(){return typeof c!=="undefined"&&!c.event.triggered?c.event.handle.apply(o.elem,arguments):w};o.elem=a;b=b.split(" ");for(var k,n=0,r;k=b[n++];){j=e?c.extend({},e):{handler:d,data:f};if(k.indexOf(".")>-1){r=k.split(".");
+k=r.shift();j.namespace=r.slice(0).sort().join(".")}else{r=[];j.namespace=""}j.type=k;j.guid=d.guid;var u=i[k],z=c.event.special[k]||{};if(!u){u=i[k]=[];if(!z.setup||z.setup.call(a,f,r,o)===false)if(a.addEventListener)a.addEventListener(k,o,false);else a.attachEvent&&a.attachEvent("on"+k,o)}if(z.add){z.add.call(a,j);if(!j.handler.guid)j.handler.guid=d.guid}u.push(j);c.event.global[k]=true}a=null}}},global:{},remove:function(a,b,d,f){if(!(a.nodeType===3||a.nodeType===8)){var e,j=0,i,o,k,n,r,u,z=c.data(a),
+C=z&&z.events;if(z&&C){if(b&&b.type){d=b.handler;b=b.type}if(!b||typeof b==="string"&&b.charAt(0)==="."){b=b||"";for(e in C)c.event.remove(a,e+b)}else{for(b=b.split(" ");e=b[j++];){n=e;i=e.indexOf(".")<0;o=[];if(!i){o=e.split(".");e=o.shift();k=new RegExp("(^|\\.)"+c.map(o.slice(0).sort(),db).join("\\.(?:.*\\.)?")+"(\\.|$)")}if(r=C[e])if(d){n=c.event.special[e]||{};for(B=f||0;B<r.length;B++){u=r[B];if(d.guid===u.guid){if(i||k.test(u.namespace)){f==null&&r.splice(B--,1);n.remove&&n.remove.call(a,u)}if(f!=
+null)break}}if(r.length===0||f!=null&&r.length===1){if(!n.teardown||n.teardown.call(a,o)===false)Ca(a,e,z.handle);delete C[e]}}else for(var B=0;B<r.length;B++){u=r[B];if(i||k.test(u.namespace)){c.event.remove(a,n,u.handler,B);r.splice(B--,1)}}}if(c.isEmptyObject(C)){if(b=z.handle)b.elem=null;delete z.events;delete z.handle;c.isEmptyObject(z)&&c.removeData(a)}}}}},trigger:function(a,b,d,f){var e=a.type||a;if(!f){a=typeof a==="object"?a[G]?a:c.extend(c.Event(e),a):c.Event(e);if(e.indexOf("!")>=0){a.type=
+e=e.slice(0,-1);a.exclusive=true}if(!d){a.stopPropagation();c.event.global[e]&&c.each(c.cache,function(){this.events&&this.events[e]&&c.event.trigger(a,b,this.handle.elem)})}if(!d||d.nodeType===3||d.nodeType===8)return w;a.result=w;a.target=d;b=c.makeArray(b);b.unshift(a)}a.currentTarget=d;(f=c.data(d,"handle"))&&f.apply(d,b);f=d.parentNode||d.ownerDocument;try{if(!(d&&d.nodeName&&c.noData[d.nodeName.toLowerCase()]))if(d["on"+e]&&d["on"+e].apply(d,b)===false)a.result=false}catch(j){}if(!a.isPropagationStopped()&&
+f)c.event.trigger(a,b,f,true);else if(!a.isDefaultPrevented()){f=a.target;var i,o=c.nodeName(f,"a")&&e==="click",k=c.event.special[e]||{};if((!k._default||k._default.call(d,a)===false)&&!o&&!(f&&f.nodeName&&c.noData[f.nodeName.toLowerCase()])){try{if(f[e]){if(i=f["on"+e])f["on"+e]=null;c.event.triggered=true;f[e]()}}catch(n){}if(i)f["on"+e]=i;c.event.triggered=false}}},handle:function(a){var b,d,f,e;a=arguments[0]=c.event.fix(a||A.event);a.currentTarget=this;b=a.type.indexOf(".")<0&&!a.exclusive;
+if(!b){d=a.type.split(".");a.type=d.shift();f=new RegExp("(^|\\.)"+d.slice(0).sort().join("\\.(?:.*\\.)?")+"(\\.|$)")}e=c.data(this,"events");d=e[a.type];if(e&&d){d=d.slice(0);e=0;for(var j=d.length;e<j;e++){var i=d[e];if(b||f.test(i.namespace)){a.handler=i.handler;a.data=i.data;a.handleObj=i;i=i.handler.apply(this,arguments);if(i!==w){a.result=i;if(i===false){a.preventDefault();a.stopPropagation()}}if(a.isImmediatePropagationStopped())break}}}return a.result},props:"altKey attrChange attrName bubbles button cancelable charCode clientX clientY ctrlKey currentTarget data detail eventPhase fromElement handler keyCode layerX layerY metaKey newValue offsetX offsetY originalTarget pageX pageY prevValue relatedNode relatedTarget screenX screenY shiftKey srcElement target toElement view wheelDelta which".split(" "),
+fix:function(a){if(a[G])return a;var b=a;a=c.Event(b);for(var d=this.props.length,f;d;){f=this.props[--d];a[f]=b[f]}if(!a.target)a.target=a.srcElement||s;if(a.target.nodeType===3)a.target=a.target.parentNode;if(!a.relatedTarget&&a.fromElement)a.relatedTarget=a.fromElement===a.target?a.toElement:a.fromElement;if(a.pageX==null&&a.clientX!=null){b=s.documentElement;d=s.body;a.pageX=a.clientX+(b&&b.scrollLeft||d&&d.scrollLeft||0)-(b&&b.clientLeft||d&&d.clientLeft||0);a.pageY=a.clientY+(b&&b.scrollTop||
+d&&d.scrollTop||0)-(b&&b.clientTop||d&&d.clientTop||0)}if(!a.which&&(a.charCode||a.charCode===0?a.charCode:a.keyCode))a.which=a.charCode||a.keyCode;if(!a.metaKey&&a.ctrlKey)a.metaKey=a.ctrlKey;if(!a.which&&a.button!==w)a.which=a.button&1?1:a.button&2?3:a.button&4?2:0;return a},guid:1E8,proxy:c.proxy,special:{ready:{setup:c.bindReady,teardown:c.noop},live:{add:function(a){c.event.add(this,a.origType,c.extend({},a,{handler:oa}))},remove:function(a){var b=true,d=a.origType.replace(O,"");c.each(c.data(this,
+"events").live||[],function(){if(d===this.origType.replace(O,""))return b=false});b&&c.event.remove(this,a.origType,oa)}},beforeunload:{setup:function(a,b,d){if(this.setInterval)this.onbeforeunload=d;return false},teardown:function(a,b){if(this.onbeforeunload===b)this.onbeforeunload=null}}}};var Ca=s.removeEventListener?function(a,b,d){a.removeEventListener(b,d,false)}:function(a,b,d){a.detachEvent("on"+b,d)};c.Event=function(a){if(!this.preventDefault)return new c.Event(a);if(a&&a.type){this.originalEvent=
+a;this.type=a.type}else this.type=a;this.timeStamp=J();this[G]=true};c.Event.prototype={preventDefault:function(){this.isDefaultPrevented=Z;var a=this.originalEvent;if(a){a.preventDefault&&a.preventDefault();a.returnValue=false}},stopPropagation:function(){this.isPropagationStopped=Z;var a=this.originalEvent;if(a){a.stopPropagation&&a.stopPropagation();a.cancelBubble=true}},stopImmediatePropagation:function(){this.isImmediatePropagationStopped=Z;this.stopPropagation()},isDefaultPrevented:Y,isPropagationStopped:Y,
+isImmediatePropagationStopped:Y};var Da=function(a){var b=a.relatedTarget;try{for(;b&&b!==this;)b=b.parentNode;if(b!==this){a.type=a.data;c.event.handle.apply(this,arguments)}}catch(d){}},Ea=function(a){a.type=a.data;c.event.handle.apply(this,arguments)};c.each({mouseenter:"mouseover",mouseleave:"mouseout"},function(a,b){c.event.special[a]={setup:function(d){c.event.add(this,b,d&&d.selector?Ea:Da,a)},teardown:function(d){c.event.remove(this,b,d&&d.selector?Ea:Da)}}});if(!c.support.submitBubbles)c.event.special.submit=
+{setup:function(){if(this.nodeName.toLowerCase()!=="form"){c.event.add(this,"click.specialSubmit",function(a){var b=a.target,d=b.type;if((d==="submit"||d==="image")&&c(b).closest("form").length)return na("submit",this,arguments)});c.event.add(this,"keypress.specialSubmit",function(a){var b=a.target,d=b.type;if((d==="text"||d==="password")&&c(b).closest("form").length&&a.keyCode===13)return na("submit",this,arguments)})}else return false},teardown:function(){c.event.remove(this,".specialSubmit")}};
+if(!c.support.changeBubbles){var da=/textarea|input|select/i,ea,Fa=function(a){var b=a.type,d=a.value;if(b==="radio"||b==="checkbox")d=a.checked;else if(b==="select-multiple")d=a.selectedIndex>-1?c.map(a.options,function(f){return f.selected}).join("-"):"";else if(a.nodeName.toLowerCase()==="select")d=a.selectedIndex;return d},fa=function(a,b){var d=a.target,f,e;if(!(!da.test(d.nodeName)||d.readOnly)){f=c.data(d,"_change_data");e=Fa(d);if(a.type!=="focusout"||d.type!=="radio")c.data(d,"_change_data",
+e);if(!(f===w||e===f))if(f!=null||e){a.type="change";return c.event.trigger(a,b,d)}}};c.event.special.change={filters:{focusout:fa,click:function(a){var b=a.target,d=b.type;if(d==="radio"||d==="checkbox"||b.nodeName.toLowerCase()==="select")return fa.call(this,a)},keydown:function(a){var b=a.target,d=b.type;if(a.keyCode===13&&b.nodeName.toLowerCase()!=="textarea"||a.keyCode===32&&(d==="checkbox"||d==="radio")||d==="select-multiple")return fa.call(this,a)},beforeactivate:function(a){a=a.target;c.data(a,
+"_change_data",Fa(a))}},setup:function(){if(this.type==="file")return false;for(var a in ea)c.event.add(this,a+".specialChange",ea[a]);return da.test(this.nodeName)},teardown:function(){c.event.remove(this,".specialChange");return da.test(this.nodeName)}};ea=c.event.special.change.filters}s.addEventListener&&c.each({focus:"focusin",blur:"focusout"},function(a,b){function d(f){f=c.event.fix(f);f.type=b;return c.event.handle.call(this,f)}c.event.special[b]={setup:function(){this.addEventListener(a,
+d,true)},teardown:function(){this.removeEventListener(a,d,true)}}});c.each(["bind","one"],function(a,b){c.fn[b]=function(d,f,e){if(typeof d==="object"){for(var j in d)this[b](j,f,d[j],e);return this}if(c.isFunction(f)){e=f;f=w}var i=b==="one"?c.proxy(e,function(k){c(this).unbind(k,i);return e.apply(this,arguments)}):e;if(d==="unload"&&b!=="one")this.one(d,f,e);else{j=0;for(var o=this.length;j<o;j++)c.event.add(this[j],d,i,f)}return this}});c.fn.extend({unbind:function(a,b){if(typeof a==="object"&&
+!a.preventDefault)for(var d in a)this.unbind(d,a[d]);else{d=0;for(var f=this.length;d<f;d++)c.event.remove(this[d],a,b)}return this},delegate:function(a,b,d,f){return this.live(b,d,f,a)},undelegate:function(a,b,d){return arguments.length===0?this.unbind("live"):this.die(b,null,d,a)},trigger:function(a,b){return this.each(function(){c.event.trigger(a,b,this)})},triggerHandler:function(a,b){if(this[0]){a=c.Event(a);a.preventDefault();a.stopPropagation();c.event.trigger(a,b,this[0]);return a.result}},
+toggle:function(a){for(var b=arguments,d=1;d<b.length;)c.proxy(a,b[d++]);return this.click(c.proxy(a,function(f){var e=(c.data(this,"lastToggle"+a.guid)||0)%d;c.data(this,"lastToggle"+a.guid,e+1);f.preventDefault();return b[e].apply(this,arguments)||false}))},hover:function(a,b){return this.mouseenter(a).mouseleave(b||a)}});var Ga={focus:"focusin",blur:"focusout",mouseenter:"mouseover",mouseleave:"mouseout"};c.each(["live","die"],function(a,b){c.fn[b]=function(d,f,e,j){var i,o=0,k,n,r=j||this.selector,
+u=j?this:c(this.context);if(c.isFunction(f)){e=f;f=w}for(d=(d||"").split(" ");(i=d[o++])!=null;){j=O.exec(i);k="";if(j){k=j[0];i=i.replace(O,"")}if(i==="hover")d.push("mouseenter"+k,"mouseleave"+k);else{n=i;if(i==="focus"||i==="blur"){d.push(Ga[i]+k);i+=k}else i=(Ga[i]||i)+k;b==="live"?u.each(function(){c.event.add(this,pa(i,r),{data:f,selector:r,handler:e,origType:i,origHandler:e,preType:n})}):u.unbind(pa(i,r),e)}}return this}});c.each("blur focus focusin focusout load resize scroll unload click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup error".split(" "),
+function(a,b){c.fn[b]=function(d){return d?this.bind(b,d):this.trigger(b)};if(c.attrFn)c.attrFn[b]=true});A.attachEvent&&!A.addEventListener&&A.attachEvent("onunload",function(){for(var a in c.cache)if(c.cache[a].handle)try{c.event.remove(c.cache[a].handle.elem)}catch(b){}});(function(){function a(g){for(var h="",l,m=0;g[m];m++){l=g[m];if(l.nodeType===3||l.nodeType===4)h+=l.nodeValue;else if(l.nodeType!==8)h+=a(l.childNodes)}return h}function b(g,h,l,m,q,p){q=0;for(var v=m.length;q<v;q++){var t=m[q];
+if(t){t=t[g];for(var y=false;t;){if(t.sizcache===l){y=m[t.sizset];break}if(t.nodeType===1&&!p){t.sizcache=l;t.sizset=q}if(t.nodeName.toLowerCase()===h){y=t;break}t=t[g]}m[q]=y}}}function d(g,h,l,m,q,p){q=0;for(var v=m.length;q<v;q++){var t=m[q];if(t){t=t[g];for(var y=false;t;){if(t.sizcache===l){y=m[t.sizset];break}if(t.nodeType===1){if(!p){t.sizcache=l;t.sizset=q}if(typeof h!=="string"){if(t===h){y=true;break}}else if(k.filter(h,[t]).length>0){y=t;break}}t=t[g]}m[q]=y}}}var f=/((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^[\]]*\]|['"][^'"]*['"]|[^[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g,
+e=0,j=Object.prototype.toString,i=false,o=true;[0,0].sort(function(){o=false;return 0});var k=function(g,h,l,m){l=l||[];var q=h=h||s;if(h.nodeType!==1&&h.nodeType!==9)return[];if(!g||typeof g!=="string")return l;for(var p=[],v,t,y,S,H=true,M=x(h),I=g;(f.exec(""),v=f.exec(I))!==null;){I=v[3];p.push(v[1]);if(v[2]){S=v[3];break}}if(p.length>1&&r.exec(g))if(p.length===2&&n.relative[p[0]])t=ga(p[0]+p[1],h);else for(t=n.relative[p[0]]?[h]:k(p.shift(),h);p.length;){g=p.shift();if(n.relative[g])g+=p.shift();
+t=ga(g,t)}else{if(!m&&p.length>1&&h.nodeType===9&&!M&&n.match.ID.test(p[0])&&!n.match.ID.test(p[p.length-1])){v=k.find(p.shift(),h,M);h=v.expr?k.filter(v.expr,v.set)[0]:v.set[0]}if(h){v=m?{expr:p.pop(),set:z(m)}:k.find(p.pop(),p.length===1&&(p[0]==="~"||p[0]==="+")&&h.parentNode?h.parentNode:h,M);t=v.expr?k.filter(v.expr,v.set):v.set;if(p.length>0)y=z(t);else H=false;for(;p.length;){var D=p.pop();v=D;if(n.relative[D])v=p.pop();else D="";if(v==null)v=h;n.relative[D](y,v,M)}}else y=[]}y||(y=t);y||k.error(D||
+g);if(j.call(y)==="[object Array]")if(H)if(h&&h.nodeType===1)for(g=0;y[g]!=null;g++){if(y[g]&&(y[g]===true||y[g].nodeType===1&&E(h,y[g])))l.push(t[g])}else for(g=0;y[g]!=null;g++)y[g]&&y[g].nodeType===1&&l.push(t[g]);else l.push.apply(l,y);else z(y,l);if(S){k(S,q,l,m);k.uniqueSort(l)}return l};k.uniqueSort=function(g){if(B){i=o;g.sort(B);if(i)for(var h=1;h<g.length;h++)g[h]===g[h-1]&&g.splice(h--,1)}return g};k.matches=function(g,h){return k(g,null,null,h)};k.find=function(g,h,l){var m,q;if(!g)return[];
+for(var p=0,v=n.order.length;p<v;p++){var t=n.order[p];if(q=n.leftMatch[t].exec(g)){var y=q[1];q.splice(1,1);if(y.substr(y.length-1)!=="\\"){q[1]=(q[1]||"").replace(/\\/g,"");m=n.find[t](q,h,l);if(m!=null){g=g.replace(n.match[t],"");break}}}}m||(m=h.getElementsByTagName("*"));return{set:m,expr:g}};k.filter=function(g,h,l,m){for(var q=g,p=[],v=h,t,y,S=h&&h[0]&&x(h[0]);g&&h.length;){for(var H in n.filter)if((t=n.leftMatch[H].exec(g))!=null&&t[2]){var M=n.filter[H],I,D;D=t[1];y=false;t.splice(1,1);if(D.substr(D.length-
+1)!=="\\"){if(v===p)p=[];if(n.preFilter[H])if(t=n.preFilter[H](t,v,l,p,m,S)){if(t===true)continue}else y=I=true;if(t)for(var U=0;(D=v[U])!=null;U++)if(D){I=M(D,t,U,v);var Ha=m^!!I;if(l&&I!=null)if(Ha)y=true;else v[U]=false;else if(Ha){p.push(D);y=true}}if(I!==w){l||(v=p);g=g.replace(n.match[H],"");if(!y)return[];break}}}if(g===q)if(y==null)k.error(g);else break;q=g}return v};k.error=function(g){throw"Syntax error, unrecognized expression: "+g;};var n=k.selectors={order:["ID","NAME","TAG"],match:{ID:/#((?:[\w\u00c0-\uFFFF-]|\\.)+)/,
+CLASS:/\.((?:[\w\u00c0-\uFFFF-]|\\.)+)/,NAME:/\[name=['"]*((?:[\w\u00c0-\uFFFF-]|\\.)+)['"]*\]/,ATTR:/\[\s*((?:[\w\u00c0-\uFFFF-]|\\.)+)\s*(?:(\S?=)\s*(['"]*)(.*?)\3|)\s*\]/,TAG:/^((?:[\w\u00c0-\uFFFF\*-]|\\.)+)/,CHILD:/:(only|nth|last|first)-child(?:\((even|odd|[\dn+-]*)\))?/,POS:/:(nth|eq|gt|lt|first|last|even|odd)(?:\((\d*)\))?(?=[^-]|$)/,PSEUDO:/:((?:[\w\u00c0-\uFFFF-]|\\.)+)(?:\((['"]?)((?:\([^\)]+\)|[^\(\)]*)+)\2\))?/},leftMatch:{},attrMap:{"class":"className","for":"htmlFor"},attrHandle:{href:function(g){return g.getAttribute("href")}},
+relative:{"+":function(g,h){var l=typeof h==="string",m=l&&!/\W/.test(h);l=l&&!m;if(m)h=h.toLowerCase();m=0;for(var q=g.length,p;m<q;m++)if(p=g[m]){for(;(p=p.previousSibling)&&p.nodeType!==1;);g[m]=l||p&&p.nodeName.toLowerCase()===h?p||false:p===h}l&&k.filter(h,g,true)},">":function(g,h){var l=typeof h==="string";if(l&&!/\W/.test(h)){h=h.toLowerCase();for(var m=0,q=g.length;m<q;m++){var p=g[m];if(p){l=p.parentNode;g[m]=l.nodeName.toLowerCase()===h?l:false}}}else{m=0;for(q=g.length;m<q;m++)if(p=g[m])g[m]=
+l?p.parentNode:p.parentNode===h;l&&k.filter(h,g,true)}},"":function(g,h,l){var m=e++,q=d;if(typeof h==="string"&&!/\W/.test(h)){var p=h=h.toLowerCase();q=b}q("parentNode",h,m,g,p,l)},"~":function(g,h,l){var m=e++,q=d;if(typeof h==="string"&&!/\W/.test(h)){var p=h=h.toLowerCase();q=b}q("previousSibling",h,m,g,p,l)}},find:{ID:function(g,h,l){if(typeof h.getElementById!=="undefined"&&!l)return(g=h.getElementById(g[1]))?[g]:[]},NAME:function(g,h){if(typeof h.getElementsByName!=="undefined"){var l=[];
+h=h.getElementsByName(g[1]);for(var m=0,q=h.length;m<q;m++)h[m].getAttribute("name")===g[1]&&l.push(h[m]);return l.length===0?null:l}},TAG:function(g,h){return h.getElementsByTagName(g[1])}},preFilter:{CLASS:function(g,h,l,m,q,p){g=" "+g[1].replace(/\\/g,"")+" ";if(p)return g;p=0;for(var v;(v=h[p])!=null;p++)if(v)if(q^(v.className&&(" "+v.className+" ").replace(/[\t\n]/g," ").indexOf(g)>=0))l||m.push(v);else if(l)h[p]=false;return false},ID:function(g){return g[1].replace(/\\/g,"")},TAG:function(g){return g[1].toLowerCase()},
+CHILD:function(g){if(g[1]==="nth"){var h=/(-?)(\d*)n((?:\+|-)?\d*)/.exec(g[2]==="even"&&"2n"||g[2]==="odd"&&"2n+1"||!/\D/.test(g[2])&&"0n+"+g[2]||g[2]);g[2]=h[1]+(h[2]||1)-0;g[3]=h[3]-0}g[0]=e++;return g},ATTR:function(g,h,l,m,q,p){h=g[1].replace(/\\/g,"");if(!p&&n.attrMap[h])g[1]=n.attrMap[h];if(g[2]==="~=")g[4]=" "+g[4]+" ";return g},PSEUDO:function(g,h,l,m,q){if(g[1]==="not")if((f.exec(g[3])||"").length>1||/^\w/.test(g[3]))g[3]=k(g[3],null,null,h);else{g=k.filter(g[3],h,l,true^q);l||m.push.apply(m,
+g);return false}else if(n.match.POS.test(g[0])||n.match.CHILD.test(g[0]))return true;return g},POS:function(g){g.unshift(true);return g}},filters:{enabled:function(g){return g.disabled===false&&g.type!=="hidden"},disabled:function(g){return g.disabled===true},checked:function(g){return g.checked===true},selected:function(g){return g.selected===true},parent:function(g){return!!g.firstChild},empty:function(g){return!g.firstChild},has:function(g,h,l){return!!k(l[3],g).length},header:function(g){return/h\d/i.test(g.nodeName)},
+text:function(g){return"text"===g.type},radio:function(g){return"radio"===g.type},checkbox:function(g){return"checkbox"===g.type},file:function(g){return"file"===g.type},password:function(g){return"password"===g.type},submit:function(g){return"submit"===g.type},image:function(g){return"image"===g.type},reset:function(g){return"reset"===g.type},button:function(g){return"button"===g.type||g.nodeName.toLowerCase()==="button"},input:function(g){return/input|select|textarea|button/i.test(g.nodeName)}},
+setFilters:{first:function(g,h){return h===0},last:function(g,h,l,m){return h===m.length-1},even:function(g,h){return h%2===0},odd:function(g,h){return h%2===1},lt:function(g,h,l){return h<l[3]-0},gt:function(g,h,l){return h>l[3]-0},nth:function(g,h,l){return l[3]-0===h},eq:function(g,h,l){return l[3]-0===h}},filter:{PSEUDO:function(g,h,l,m){var q=h[1],p=n.filters[q];if(p)return p(g,l,h,m);else if(q==="contains")return(g.textContent||g.innerText||a([g])||"").indexOf(h[3])>=0;else if(q==="not"){h=
+h[3];l=0;for(m=h.length;l<m;l++)if(h[l]===g)return false;return true}else k.error("Syntax error, unrecognized expression: "+q)},CHILD:function(g,h){var l=h[1],m=g;switch(l){case "only":case "first":for(;m=m.previousSibling;)if(m.nodeType===1)return false;if(l==="first")return true;m=g;case "last":for(;m=m.nextSibling;)if(m.nodeType===1)return false;return true;case "nth":l=h[2];var q=h[3];if(l===1&&q===0)return true;h=h[0];var p=g.parentNode;if(p&&(p.sizcache!==h||!g.nodeIndex)){var v=0;for(m=p.firstChild;m;m=
+m.nextSibling)if(m.nodeType===1)m.nodeIndex=++v;p.sizcache=h}g=g.nodeIndex-q;return l===0?g===0:g%l===0&&g/l>=0}},ID:function(g,h){return g.nodeType===1&&g.getAttribute("id")===h},TAG:function(g,h){return h==="*"&&g.nodeType===1||g.nodeName.toLowerCase()===h},CLASS:function(g,h){return(" "+(g.className||g.getAttribute("class"))+" ").indexOf(h)>-1},ATTR:function(g,h){var l=h[1];g=n.attrHandle[l]?n.attrHandle[l](g):g[l]!=null?g[l]:g.getAttribute(l);l=g+"";var m=h[2];h=h[4];return g==null?m==="!=":m===
+"="?l===h:m==="*="?l.indexOf(h)>=0:m==="~="?(" "+l+" ").indexOf(h)>=0:!h?l&&g!==false:m==="!="?l!==h:m==="^="?l.indexOf(h)===0:m==="$="?l.substr(l.length-h.length)===h:m==="|="?l===h||l.substr(0,h.length+1)===h+"-":false},POS:function(g,h,l,m){var q=n.setFilters[h[2]];if(q)return q(g,l,h,m)}}},r=n.match.POS;for(var u in n.match){n.match[u]=new RegExp(n.match[u].source+/(?![^\[]*\])(?![^\(]*\))/.source);n.leftMatch[u]=new RegExp(/(^(?:.|\r|\n)*?)/.source+n.match[u].source.replace(/\\(\d+)/g,function(g,
+h){return"\\"+(h-0+1)}))}var z=function(g,h){g=Array.prototype.slice.call(g,0);if(h){h.push.apply(h,g);return h}return g};try{Array.prototype.slice.call(s.documentElement.childNodes,0)}catch(C){z=function(g,h){h=h||[];if(j.call(g)==="[object Array]")Array.prototype.push.apply(h,g);else if(typeof g.length==="number")for(var l=0,m=g.length;l<m;l++)h.push(g[l]);else for(l=0;g[l];l++)h.push(g[l]);return h}}var B;if(s.documentElement.compareDocumentPosition)B=function(g,h){if(!g.compareDocumentPosition||
+!h.compareDocumentPosition){if(g==h)i=true;return g.compareDocumentPosition?-1:1}g=g.compareDocumentPosition(h)&4?-1:g===h?0:1;if(g===0)i=true;return g};else if("sourceIndex"in s.documentElement)B=function(g,h){if(!g.sourceIndex||!h.sourceIndex){if(g==h)i=true;return g.sourceIndex?-1:1}g=g.sourceIndex-h.sourceIndex;if(g===0)i=true;return g};else if(s.createRange)B=function(g,h){if(!g.ownerDocument||!h.ownerDocument){if(g==h)i=true;return g.ownerDocument?-1:1}var l=g.ownerDocument.createRange(),m=
+h.ownerDocument.createRange();l.setStart(g,0);l.setEnd(g,0);m.setStart(h,0);m.setEnd(h,0);g=l.compareBoundaryPoints(Range.START_TO_END,m);if(g===0)i=true;return g};(function(){var g=s.createElement("div"),h="script"+(new Date).getTime();g.innerHTML="<a name='"+h+"'/>";var l=s.documentElement;l.insertBefore(g,l.firstChild);if(s.getElementById(h)){n.find.ID=function(m,q,p){if(typeof q.getElementById!=="undefined"&&!p)return(q=q.getElementById(m[1]))?q.id===m[1]||typeof q.getAttributeNode!=="undefined"&&
+q.getAttributeNode("id").nodeValue===m[1]?[q]:w:[]};n.filter.ID=function(m,q){var p=typeof m.getAttributeNode!=="undefined"&&m.getAttributeNode("id");return m.nodeType===1&&p&&p.nodeValue===q}}l.removeChild(g);l=g=null})();(function(){var g=s.createElement("div");g.appendChild(s.createComment(""));if(g.getElementsByTagName("*").length>0)n.find.TAG=function(h,l){l=l.getElementsByTagName(h[1]);if(h[1]==="*"){h=[];for(var m=0;l[m];m++)l[m].nodeType===1&&h.push(l[m]);l=h}return l};g.innerHTML="<a href='#'></a>";
+if(g.firstChild&&typeof g.firstChild.getAttribute!=="undefined"&&g.firstChild.getAttribute("href")!=="#")n.attrHandle.href=function(h){return h.getAttribute("href",2)};g=null})();s.querySelectorAll&&function(){var g=k,h=s.createElement("div");h.innerHTML="<p class='TEST'></p>";if(!(h.querySelectorAll&&h.querySelectorAll(".TEST").length===0)){k=function(m,q,p,v){q=q||s;if(!v&&q.nodeType===9&&!x(q))try{return z(q.querySelectorAll(m),p)}catch(t){}return g(m,q,p,v)};for(var l in g)k[l]=g[l];h=null}}();
+(function(){var g=s.createElement("div");g.innerHTML="<div class='test e'></div><div class='test'></div>";if(!(!g.getElementsByClassName||g.getElementsByClassName("e").length===0)){g.lastChild.className="e";if(g.getElementsByClassName("e").length!==1){n.order.splice(1,0,"CLASS");n.find.CLASS=function(h,l,m){if(typeof l.getElementsByClassName!=="undefined"&&!m)return l.getElementsByClassName(h[1])};g=null}}})();var E=s.compareDocumentPosition?function(g,h){return!!(g.compareDocumentPosition(h)&16)}:
+function(g,h){return g!==h&&(g.contains?g.contains(h):true)},x=function(g){return(g=(g?g.ownerDocument||g:0).documentElement)?g.nodeName!=="HTML":false},ga=function(g,h){var l=[],m="",q;for(h=h.nodeType?[h]:h;q=n.match.PSEUDO.exec(g);){m+=q[0];g=g.replace(n.match.PSEUDO,"")}g=n.relative[g]?g+"*":g;q=0;for(var p=h.length;q<p;q++)k(g,h[q],l);return k.filter(m,l)};c.find=k;c.expr=k.selectors;c.expr[":"]=c.expr.filters;c.unique=k.uniqueSort;c.text=a;c.isXMLDoc=x;c.contains=E})();var eb=/Until$/,fb=/^(?:parents|prevUntil|prevAll)/,
+gb=/,/;R=Array.prototype.slice;var Ia=function(a,b,d){if(c.isFunction(b))return c.grep(a,function(e,j){return!!b.call(e,j,e)===d});else if(b.nodeType)return c.grep(a,function(e){return e===b===d});else if(typeof b==="string"){var f=c.grep(a,function(e){return e.nodeType===1});if(Ua.test(b))return c.filter(b,f,!d);else b=c.filter(b,f)}return c.grep(a,function(e){return c.inArray(e,b)>=0===d})};c.fn.extend({find:function(a){for(var b=this.pushStack("","find",a),d=0,f=0,e=this.length;f<e;f++){d=b.length;
+c.find(a,this[f],b);if(f>0)for(var j=d;j<b.length;j++)for(var i=0;i<d;i++)if(b[i]===b[j]){b.splice(j--,1);break}}return b},has:function(a){var b=c(a);return this.filter(function(){for(var d=0,f=b.length;d<f;d++)if(c.contains(this,b[d]))return true})},not:function(a){return this.pushStack(Ia(this,a,false),"not",a)},filter:function(a){return this.pushStack(Ia(this,a,true),"filter",a)},is:function(a){return!!a&&c.filter(a,this).length>0},closest:function(a,b){if(c.isArray(a)){var d=[],f=this[0],e,j=
+{},i;if(f&&a.length){e=0;for(var o=a.length;e<o;e++){i=a[e];j[i]||(j[i]=c.expr.match.POS.test(i)?c(i,b||this.context):i)}for(;f&&f.ownerDocument&&f!==b;){for(i in j){e=j[i];if(e.jquery?e.index(f)>-1:c(f).is(e)){d.push({selector:i,elem:f});delete j[i]}}f=f.parentNode}}return d}var k=c.expr.match.POS.test(a)?c(a,b||this.context):null;return this.map(function(n,r){for(;r&&r.ownerDocument&&r!==b;){if(k?k.index(r)>-1:c(r).is(a))return r;r=r.parentNode}return null})},index:function(a){if(!a||typeof a===
+"string")return c.inArray(this[0],a?c(a):this.parent().children());return c.inArray(a.jquery?a[0]:a,this)},add:function(a,b){a=typeof a==="string"?c(a,b||this.context):c.makeArray(a);b=c.merge(this.get(),a);return this.pushStack(qa(a[0])||qa(b[0])?b:c.unique(b))},andSelf:function(){return this.add(this.prevObject)}});c.each({parent:function(a){return(a=a.parentNode)&&a.nodeType!==11?a:null},parents:function(a){return c.dir(a,"parentNode")},parentsUntil:function(a,b,d){return c.dir(a,"parentNode",
+d)},next:function(a){return c.nth(a,2,"nextSibling")},prev:function(a){return c.nth(a,2,"previousSibling")},nextAll:function(a){return c.dir(a,"nextSibling")},prevAll:function(a){return c.dir(a,"previousSibling")},nextUntil:function(a,b,d){return c.dir(a,"nextSibling",d)},prevUntil:function(a,b,d){return c.dir(a,"previousSibling",d)},siblings:function(a){return c.sibling(a.parentNode.firstChild,a)},children:function(a){return c.sibling(a.firstChild)},contents:function(a){return c.nodeName(a,"iframe")?
+a.contentDocument||a.contentWindow.document:c.makeArray(a.childNodes)}},function(a,b){c.fn[a]=function(d,f){var e=c.map(this,b,d);eb.test(a)||(f=d);if(f&&typeof f==="string")e=c.filter(f,e);e=this.length>1?c.unique(e):e;if((this.length>1||gb.test(f))&&fb.test(a))e=e.reverse();return this.pushStack(e,a,R.call(arguments).join(","))}});c.extend({filter:function(a,b,d){if(d)a=":not("+a+")";return c.find.matches(a,b)},dir:function(a,b,d){var f=[];for(a=a[b];a&&a.nodeType!==9&&(d===w||a.nodeType!==1||!c(a).is(d));){a.nodeType===
+1&&f.push(a);a=a[b]}return f},nth:function(a,b,d){b=b||1;for(var f=0;a;a=a[d])if(a.nodeType===1&&++f===b)break;return a},sibling:function(a,b){for(var d=[];a;a=a.nextSibling)a.nodeType===1&&a!==b&&d.push(a);return d}});var Ja=/ jQuery\d+="(?:\d+|null)"/g,V=/^\s+/,Ka=/(<([\w:]+)[^>]*?)\/>/g,hb=/^(?:area|br|col|embed|hr|img|input|link|meta|param)$/i,La=/<([\w:]+)/,ib=/<tbody/i,jb=/<|&#?\w+;/,ta=/<script|<object|<embed|<option|<style/i,ua=/checked\s*(?:[^=]|=\s*.checked.)/i,Ma=function(a,b,d){return hb.test(d)?
+a:b+"></"+d+">"},F={option:[1,"<select multiple='multiple'>","</select>"],legend:[1,"<fieldset>","</fieldset>"],thead:[1,"<table>","</table>"],tr:[2,"<table><tbody>","</tbody></table>"],td:[3,"<table><tbody><tr>","</tr></tbody></table>"],col:[2,"<table><tbody></tbody><colgroup>","</colgroup></table>"],area:[1,"<map>","</map>"],_default:[0,"",""]};F.optgroup=F.option;F.tbody=F.tfoot=F.colgroup=F.caption=F.thead;F.th=F.td;if(!c.support.htmlSerialize)F._default=[1,"div<div>","</div>"];c.fn.extend({text:function(a){if(c.isFunction(a))return this.each(function(b){var d=
+c(this);d.text(a.call(this,b,d.text()))});if(typeof a!=="object"&&a!==w)return this.empty().append((this[0]&&this[0].ownerDocument||s).createTextNode(a));return c.text(this)},wrapAll:function(a){if(c.isFunction(a))return this.each(function(d){c(this).wrapAll(a.call(this,d))});if(this[0]){var b=c(a,this[0].ownerDocument).eq(0).clone(true);this[0].parentNode&&b.insertBefore(this[0]);b.map(function(){for(var d=this;d.firstChild&&d.firstChild.nodeType===1;)d=d.firstChild;return d}).append(this)}return this},
+wrapInner:function(a){if(c.isFunction(a))return this.each(function(b){c(this).wrapInner(a.call(this,b))});return this.each(function(){var b=c(this),d=b.contents();d.length?d.wrapAll(a):b.append(a)})},wrap:function(a){return this.each(function(){c(this).wrapAll(a)})},unwrap:function(){return this.parent().each(function(){c.nodeName(this,"body")||c(this).replaceWith(this.childNodes)}).end()},append:function(){return this.domManip(arguments,true,function(a){this.nodeType===1&&this.appendChild(a)})},
+prepend:function(){return this.domManip(arguments,true,function(a){this.nodeType===1&&this.insertBefore(a,this.firstChild)})},before:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,false,function(b){this.parentNode.insertBefore(b,this)});else if(arguments.length){var a=c(arguments[0]);a.push.apply(a,this.toArray());return this.pushStack(a,"before",arguments)}},after:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,false,function(b){this.parentNode.insertBefore(b,
+this.nextSibling)});else if(arguments.length){var a=this.pushStack(this,"after",arguments);a.push.apply(a,c(arguments[0]).toArray());return a}},remove:function(a,b){for(var d=0,f;(f=this[d])!=null;d++)if(!a||c.filter(a,[f]).length){if(!b&&f.nodeType===1){c.cleanData(f.getElementsByTagName("*"));c.cleanData([f])}f.parentNode&&f.parentNode.removeChild(f)}return this},empty:function(){for(var a=0,b;(b=this[a])!=null;a++)for(b.nodeType===1&&c.cleanData(b.getElementsByTagName("*"));b.firstChild;)b.removeChild(b.firstChild);
+return this},clone:function(a){var b=this.map(function(){if(!c.support.noCloneEvent&&!c.isXMLDoc(this)){var d=this.outerHTML,f=this.ownerDocument;if(!d){d=f.createElement("div");d.appendChild(this.cloneNode(true));d=d.innerHTML}return c.clean([d.replace(Ja,"").replace(/=([^="'>\s]+\/)>/g,'="$1">').replace(V,"")],f)[0]}else return this.cloneNode(true)});if(a===true){ra(this,b);ra(this.find("*"),b.find("*"))}return b},html:function(a){if(a===w)return this[0]&&this[0].nodeType===1?this[0].innerHTML.replace(Ja,
+""):null;else if(typeof a==="string"&&!ta.test(a)&&(c.support.leadingWhitespace||!V.test(a))&&!F[(La.exec(a)||["",""])[1].toLowerCase()]){a=a.replace(Ka,Ma);try{for(var b=0,d=this.length;b<d;b++)if(this[b].nodeType===1){c.cleanData(this[b].getElementsByTagName("*"));this[b].innerHTML=a}}catch(f){this.empty().append(a)}}else c.isFunction(a)?this.each(function(e){var j=c(this),i=j.html();j.empty().append(function(){return a.call(this,e,i)})}):this.empty().append(a);return this},replaceWith:function(a){if(this[0]&&
+this[0].parentNode){if(c.isFunction(a))return this.each(function(b){var d=c(this),f=d.html();d.replaceWith(a.call(this,b,f))});if(typeof a!=="string")a=c(a).detach();return this.each(function(){var b=this.nextSibling,d=this.parentNode;c(this).remove();b?c(b).before(a):c(d).append(a)})}else return this.pushStack(c(c.isFunction(a)?a():a),"replaceWith",a)},detach:function(a){return this.remove(a,true)},domManip:function(a,b,d){function f(u){return c.nodeName(u,"table")?u.getElementsByTagName("tbody")[0]||
+u.appendChild(u.ownerDocument.createElement("tbody")):u}var e,j,i=a[0],o=[],k;if(!c.support.checkClone&&arguments.length===3&&typeof i==="string"&&ua.test(i))return this.each(function(){c(this).domManip(a,b,d,true)});if(c.isFunction(i))return this.each(function(u){var z=c(this);a[0]=i.call(this,u,b?z.html():w);z.domManip(a,b,d)});if(this[0]){e=i&&i.parentNode;e=c.support.parentNode&&e&&e.nodeType===11&&e.childNodes.length===this.length?{fragment:e}:sa(a,this,o);k=e.fragment;if(j=k.childNodes.length===
+1?(k=k.firstChild):k.firstChild){b=b&&c.nodeName(j,"tr");for(var n=0,r=this.length;n<r;n++)d.call(b?f(this[n],j):this[n],n>0||e.cacheable||this.length>1?k.cloneNode(true):k)}o.length&&c.each(o,Qa)}return this}});c.fragments={};c.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(a,b){c.fn[a]=function(d){var f=[];d=c(d);var e=this.length===1&&this[0].parentNode;if(e&&e.nodeType===11&&e.childNodes.length===1&&d.length===1){d[b](this[0]);
+return this}else{e=0;for(var j=d.length;e<j;e++){var i=(e>0?this.clone(true):this).get();c.fn[b].apply(c(d[e]),i);f=f.concat(i)}return this.pushStack(f,a,d.selector)}}});c.extend({clean:function(a,b,d,f){b=b||s;if(typeof b.createElement==="undefined")b=b.ownerDocument||b[0]&&b[0].ownerDocument||s;for(var e=[],j=0,i;(i=a[j])!=null;j++){if(typeof i==="number")i+="";if(i){if(typeof i==="string"&&!jb.test(i))i=b.createTextNode(i);else if(typeof i==="string"){i=i.replace(Ka,Ma);var o=(La.exec(i)||["",
+""])[1].toLowerCase(),k=F[o]||F._default,n=k[0],r=b.createElement("div");for(r.innerHTML=k[1]+i+k[2];n--;)r=r.lastChild;if(!c.support.tbody){n=ib.test(i);o=o==="table"&&!n?r.firstChild&&r.firstChild.childNodes:k[1]==="<table>"&&!n?r.childNodes:[];for(k=o.length-1;k>=0;--k)c.nodeName(o[k],"tbody")&&!o[k].childNodes.length&&o[k].parentNode.removeChild(o[k])}!c.support.leadingWhitespace&&V.test(i)&&r.insertBefore(b.createTextNode(V.exec(i)[0]),r.firstChild);i=r.childNodes}if(i.nodeType)e.push(i);else e=
+c.merge(e,i)}}if(d)for(j=0;e[j];j++)if(f&&c.nodeName(e[j],"script")&&(!e[j].type||e[j].type.toLowerCase()==="text/javascript"))f.push(e[j].parentNode?e[j].parentNode.removeChild(e[j]):e[j]);else{e[j].nodeType===1&&e.splice.apply(e,[j+1,0].concat(c.makeArray(e[j].getElementsByTagName("script"))));d.appendChild(e[j])}return e},cleanData:function(a){for(var b,d,f=c.cache,e=c.event.special,j=c.support.deleteExpando,i=0,o;(o=a[i])!=null;i++)if(d=o[c.expando]){b=f[d];if(b.events)for(var k in b.events)e[k]?
+c.event.remove(o,k):Ca(o,k,b.handle);if(j)delete o[c.expando];else o.removeAttribute&&o.removeAttribute(c.expando);delete f[d]}}});var kb=/z-?index|font-?weight|opacity|zoom|line-?height/i,Na=/alpha\([^)]*\)/,Oa=/opacity=([^)]*)/,ha=/float/i,ia=/-([a-z])/ig,lb=/([A-Z])/g,mb=/^-?\d+(?:px)?$/i,nb=/^-?\d/,ob={position:"absolute",visibility:"hidden",display:"block"},pb=["Left","Right"],qb=["Top","Bottom"],rb=s.defaultView&&s.defaultView.getComputedStyle,Pa=c.support.cssFloat?"cssFloat":"styleFloat",ja=
+function(a,b){return b.toUpperCase()};c.fn.css=function(a,b){return X(this,a,b,true,function(d,f,e){if(e===w)return c.curCSS(d,f);if(typeof e==="number"&&!kb.test(f))e+="px";c.style(d,f,e)})};c.extend({style:function(a,b,d){if(!a||a.nodeType===3||a.nodeType===8)return w;if((b==="width"||b==="height")&&parseFloat(d)<0)d=w;var f=a.style||a,e=d!==w;if(!c.support.opacity&&b==="opacity"){if(e){f.zoom=1;b=parseInt(d,10)+""==="NaN"?"":"alpha(opacity="+d*100+")";a=f.filter||c.curCSS(a,"filter")||"";f.filter=
+Na.test(a)?a.replace(Na,b):b}return f.filter&&f.filter.indexOf("opacity=")>=0?parseFloat(Oa.exec(f.filter)[1])/100+"":""}if(ha.test(b))b=Pa;b=b.replace(ia,ja);if(e)f[b]=d;return f[b]},css:function(a,b,d,f){if(b==="width"||b==="height"){var e,j=b==="width"?pb:qb;function i(){e=b==="width"?a.offsetWidth:a.offsetHeight;f!=="border"&&c.each(j,function(){f||(e-=parseFloat(c.curCSS(a,"padding"+this,true))||0);if(f==="margin")e+=parseFloat(c.curCSS(a,"margin"+this,true))||0;else e-=parseFloat(c.curCSS(a,
+"border"+this+"Width",true))||0})}a.offsetWidth!==0?i():c.swap(a,ob,i);return Math.max(0,Math.round(e))}return c.curCSS(a,b,d)},curCSS:function(a,b,d){var f,e=a.style;if(!c.support.opacity&&b==="opacity"&&a.currentStyle){f=Oa.test(a.currentStyle.filter||"")?parseFloat(RegExp.$1)/100+"":"";return f===""?"1":f}if(ha.test(b))b=Pa;if(!d&&e&&e[b])f=e[b];else if(rb){if(ha.test(b))b="float";b=b.replace(lb,"-$1").toLowerCase();e=a.ownerDocument.defaultView;if(!e)return null;if(a=e.getComputedStyle(a,null))f=
+a.getPropertyValue(b);if(b==="opacity"&&f==="")f="1"}else if(a.currentStyle){d=b.replace(ia,ja);f=a.currentStyle[b]||a.currentStyle[d];if(!mb.test(f)&&nb.test(f)){b=e.left;var j=a.runtimeStyle.left;a.runtimeStyle.left=a.currentStyle.left;e.left=d==="fontSize"?"1em":f||0;f=e.pixelLeft+"px";e.left=b;a.runtimeStyle.left=j}}return f},swap:function(a,b,d){var f={};for(var e in b){f[e]=a.style[e];a.style[e]=b[e]}d.call(a);for(e in b)a.style[e]=f[e]}});if(c.expr&&c.expr.filters){c.expr.filters.hidden=function(a){var b=
+a.offsetWidth,d=a.offsetHeight,f=a.nodeName.toLowerCase()==="tr";return b===0&&d===0&&!f?true:b>0&&d>0&&!f?false:c.curCSS(a,"display")==="none"};c.expr.filters.visible=function(a){return!c.expr.filters.hidden(a)}}var sb=J(),tb=/<script(.|\s)*?\/script>/gi,ub=/select|textarea/i,vb=/color|date|datetime|email|hidden|month|number|password|range|search|tel|text|time|url|week/i,N=/=\?(&|$)/,ka=/\?/,wb=/(\?|&)_=.*?(&|$)/,xb=/^(\w+:)?\/\/([^\/?#]+)/,yb=/%20/g,zb=c.fn.load;c.fn.extend({load:function(a,b,d){if(typeof a!==
+"string")return zb.call(this,a);else if(!this.length)return this;var f=a.indexOf(" ");if(f>=0){var e=a.slice(f,a.length);a=a.slice(0,f)}f="GET";if(b)if(c.isFunction(b)){d=b;b=null}else if(typeof b==="object"){b=c.param(b,c.ajaxSettings.traditional);f="POST"}var j=this;c.ajax({url:a,type:f,dataType:"html",data:b,complete:function(i,o){if(o==="success"||o==="notmodified")j.html(e?c("<div />").append(i.responseText.replace(tb,"")).find(e):i.responseText);d&&j.each(d,[i.responseText,o,i])}});return this},
+serialize:function(){return c.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?c.makeArray(this.elements):this}).filter(function(){return this.name&&!this.disabled&&(this.checked||ub.test(this.nodeName)||vb.test(this.type))}).map(function(a,b){a=c(this).val();return a==null?null:c.isArray(a)?c.map(a,function(d){return{name:b.name,value:d}}):{name:b.name,value:a}}).get()}});c.each("ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split(" "),
+function(a,b){c.fn[b]=function(d){return this.bind(b,d)}});c.extend({get:function(a,b,d,f){if(c.isFunction(b)){f=f||d;d=b;b=null}return c.ajax({type:"GET",url:a,data:b,success:d,dataType:f})},getScript:function(a,b){return c.get(a,null,b,"script")},getJSON:function(a,b,d){return c.get(a,b,d,"json")},post:function(a,b,d,f){if(c.isFunction(b)){f=f||d;d=b;b={}}return c.ajax({type:"POST",url:a,data:b,success:d,dataType:f})},ajaxSetup:function(a){c.extend(c.ajaxSettings,a)},ajaxSettings:{url:location.href,
+global:true,type:"GET",contentType:"application/x-www-form-urlencoded",processData:true,async:true,xhr:A.XMLHttpRequest&&(A.location.protocol!=="file:"||!A.ActiveXObject)?function(){return new A.XMLHttpRequest}:function(){try{return new A.ActiveXObject("Microsoft.XMLHTTP")}catch(a){}},accepts:{xml:"application/xml, text/xml",html:"text/html",script:"text/javascript, application/javascript",json:"application/json, text/javascript",text:"text/plain",_default:"*/*"}},lastModified:{},etag:{},ajax:function(a){function b(){e.success&&
+e.success.call(k,o,i,x);e.global&&f("ajaxSuccess",[x,e])}function d(){e.complete&&e.complete.call(k,x,i);e.global&&f("ajaxComplete",[x,e]);e.global&&!--c.active&&c.event.trigger("ajaxStop")}function f(q,p){(e.context?c(e.context):c.event).trigger(q,p)}var e=c.extend(true,{},c.ajaxSettings,a),j,i,o,k=a&&a.context||e,n=e.type.toUpperCase();if(e.data&&e.processData&&typeof e.data!=="string")e.data=c.param(e.data,e.traditional);if(e.dataType==="jsonp"){if(n==="GET")N.test(e.url)||(e.url+=(ka.test(e.url)?
+"&":"?")+(e.jsonp||"callback")+"=?");else if(!e.data||!N.test(e.data))e.data=(e.data?e.data+"&":"")+(e.jsonp||"callback")+"=?";e.dataType="json"}if(e.dataType==="json"&&(e.data&&N.test(e.data)||N.test(e.url))){j=e.jsonpCallback||"jsonp"+sb++;if(e.data)e.data=(e.data+"").replace(N,"="+j+"$1");e.url=e.url.replace(N,"="+j+"$1");e.dataType="script";A[j]=A[j]||function(q){o=q;b();d();A[j]=w;try{delete A[j]}catch(p){}z&&z.removeChild(C)}}if(e.dataType==="script"&&e.cache===null)e.cache=false;if(e.cache===
+false&&n==="GET"){var r=J(),u=e.url.replace(wb,"$1_="+r+"$2");e.url=u+(u===e.url?(ka.test(e.url)?"&":"?")+"_="+r:"")}if(e.data&&n==="GET")e.url+=(ka.test(e.url)?"&":"?")+e.data;e.global&&!c.active++&&c.event.trigger("ajaxStart");r=(r=xb.exec(e.url))&&(r[1]&&r[1]!==location.protocol||r[2]!==location.host);if(e.dataType==="script"&&n==="GET"&&r){var z=s.getElementsByTagName("head")[0]||s.documentElement,C=s.createElement("script");C.src=e.url;if(e.scriptCharset)C.charset=e.scriptCharset;if(!j){var B=
+false;C.onload=C.onreadystatechange=function(){if(!B&&(!this.readyState||this.readyState==="loaded"||this.readyState==="complete")){B=true;b();d();C.onload=C.onreadystatechange=null;z&&C.parentNode&&z.removeChild(C)}}}z.insertBefore(C,z.firstChild);return w}var E=false,x=e.xhr();if(x){e.username?x.open(n,e.url,e.async,e.username,e.password):x.open(n,e.url,e.async);try{if(e.data||a&&a.contentType)x.setRequestHeader("Content-Type",e.contentType);if(e.ifModified){c.lastModified[e.url]&&x.setRequestHeader("If-Modified-Since",
+c.lastModified[e.url]);c.etag[e.url]&&x.setRequestHeader("If-None-Match",c.etag[e.url])}r||x.setRequestHeader("X-Requested-With","XMLHttpRequest");x.setRequestHeader("Accept",e.dataType&&e.accepts[e.dataType]?e.accepts[e.dataType]+", */*":e.accepts._default)}catch(ga){}if(e.beforeSend&&e.beforeSend.call(k,x,e)===false){e.global&&!--c.active&&c.event.trigger("ajaxStop");x.abort();return false}e.global&&f("ajaxSend",[x,e]);var g=x.onreadystatechange=function(q){if(!x||x.readyState===0||q==="abort"){E||
+d();E=true;if(x)x.onreadystatechange=c.noop}else if(!E&&x&&(x.readyState===4||q==="timeout")){E=true;x.onreadystatechange=c.noop;i=q==="timeout"?"timeout":!c.httpSuccess(x)?"error":e.ifModified&&c.httpNotModified(x,e.url)?"notmodified":"success";var p;if(i==="success")try{o=c.httpData(x,e.dataType,e)}catch(v){i="parsererror";p=v}if(i==="success"||i==="notmodified")j||b();else c.handleError(e,x,i,p);d();q==="timeout"&&x.abort();if(e.async)x=null}};try{var h=x.abort;x.abort=function(){x&&h.call(x);
+g("abort")}}catch(l){}e.async&&e.timeout>0&&setTimeout(function(){x&&!E&&g("timeout")},e.timeout);try{x.send(n==="POST"||n==="PUT"||n==="DELETE"?e.data:null)}catch(m){c.handleError(e,x,null,m);d()}e.async||g();return x}},handleError:function(a,b,d,f){if(a.error)a.error.call(a.context||a,b,d,f);if(a.global)(a.context?c(a.context):c.event).trigger("ajaxError",[b,a,f])},active:0,httpSuccess:function(a){try{return!a.status&&location.protocol==="file:"||a.status>=200&&a.status<300||a.status===304||a.status===
+1223||a.status===0}catch(b){}return false},httpNotModified:function(a,b){var d=a.getResponseHeader("Last-Modified"),f=a.getResponseHeader("Etag");if(d)c.lastModified[b]=d;if(f)c.etag[b]=f;return a.status===304||a.status===0},httpData:function(a,b,d){var f=a.getResponseHeader("content-type")||"",e=b==="xml"||!b&&f.indexOf("xml")>=0;a=e?a.responseXML:a.responseText;e&&a.documentElement.nodeName==="parsererror"&&c.error("parsererror");if(d&&d.dataFilter)a=d.dataFilter(a,b);if(typeof a==="string")if(b===
+"json"||!b&&f.indexOf("json")>=0)a=c.parseJSON(a);else if(b==="script"||!b&&f.indexOf("javascript")>=0)c.globalEval(a);return a},param:function(a,b){function d(i,o){if(c.isArray(o))c.each(o,function(k,n){b||/\[\]$/.test(i)?f(i,n):d(i+"["+(typeof n==="object"||c.isArray(n)?k:"")+"]",n)});else!b&&o!=null&&typeof o==="object"?c.each(o,function(k,n){d(i+"["+k+"]",n)}):f(i,o)}function f(i,o){o=c.isFunction(o)?o():o;e[e.length]=encodeURIComponent(i)+"="+encodeURIComponent(o)}var e=[];if(b===w)b=c.ajaxSettings.traditional;
+if(c.isArray(a)||a.jquery)c.each(a,function(){f(this.name,this.value)});else for(var j in a)d(j,a[j]);return e.join("&").replace(yb,"+")}});var la={},Ab=/toggle|show|hide/,Bb=/^([+-]=)?([\d+-.]+)(.*)$/,W,va=[["height","marginTop","marginBottom","paddingTop","paddingBottom"],["width","marginLeft","marginRight","paddingLeft","paddingRight"],["opacity"]];c.fn.extend({show:function(a,b){if(a||a===0)return this.animate(K("show",3),a,b);else{a=0;for(b=this.length;a<b;a++){var d=c.data(this[a],"olddisplay");
+this[a].style.display=d||"";if(c.css(this[a],"display")==="none"){d=this[a].nodeName;var f;if(la[d])f=la[d];else{var e=c("<"+d+" />").appendTo("body");f=e.css("display");if(f==="none")f="block";e.remove();la[d]=f}c.data(this[a],"olddisplay",f)}}a=0;for(b=this.length;a<b;a++)this[a].style.display=c.data(this[a],"olddisplay")||"";return this}},hide:function(a,b){if(a||a===0)return this.animate(K("hide",3),a,b);else{a=0;for(b=this.length;a<b;a++){var d=c.data(this[a],"olddisplay");!d&&d!=="none"&&c.data(this[a],
+"olddisplay",c.css(this[a],"display"))}a=0;for(b=this.length;a<b;a++)this[a].style.display="none";return this}},_toggle:c.fn.toggle,toggle:function(a,b){var d=typeof a==="boolean";if(c.isFunction(a)&&c.isFunction(b))this._toggle.apply(this,arguments);else a==null||d?this.each(function(){var f=d?a:c(this).is(":hidden");c(this)[f?"show":"hide"]()}):this.animate(K("toggle",3),a,b);return this},fadeTo:function(a,b,d){return this.filter(":hidden").css("opacity",0).show().end().animate({opacity:b},a,d)},
+animate:function(a,b,d,f){var e=c.speed(b,d,f);if(c.isEmptyObject(a))return this.each(e.complete);return this[e.queue===false?"each":"queue"](function(){var j=c.extend({},e),i,o=this.nodeType===1&&c(this).is(":hidden"),k=this;for(i in a){var n=i.replace(ia,ja);if(i!==n){a[n]=a[i];delete a[i];i=n}if(a[i]==="hide"&&o||a[i]==="show"&&!o)return j.complete.call(this);if((i==="height"||i==="width")&&this.style){j.display=c.css(this,"display");j.overflow=this.style.overflow}if(c.isArray(a[i])){(j.specialEasing=
+j.specialEasing||{})[i]=a[i][1];a[i]=a[i][0]}}if(j.overflow!=null)this.style.overflow="hidden";j.curAnim=c.extend({},a);c.each(a,function(r,u){var z=new c.fx(k,j,r);if(Ab.test(u))z[u==="toggle"?o?"show":"hide":u](a);else{var C=Bb.exec(u),B=z.cur(true)||0;if(C){u=parseFloat(C[2]);var E=C[3]||"px";if(E!=="px"){k.style[r]=(u||1)+E;B=(u||1)/z.cur(true)*B;k.style[r]=B+E}if(C[1])u=(C[1]==="-="?-1:1)*u+B;z.custom(B,u,E)}else z.custom(B,u,"")}});return true})},stop:function(a,b){var d=c.timers;a&&this.queue([]);
+this.each(function(){for(var f=d.length-1;f>=0;f--)if(d[f].elem===this){b&&d[f](true);d.splice(f,1)}});b||this.dequeue();return this}});c.each({slideDown:K("show",1),slideUp:K("hide",1),slideToggle:K("toggle",1),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"}},function(a,b){c.fn[a]=function(d,f){return this.animate(b,d,f)}});c.extend({speed:function(a,b,d){var f=a&&typeof a==="object"?a:{complete:d||!d&&b||c.isFunction(a)&&a,duration:a,easing:d&&b||b&&!c.isFunction(b)&&b};f.duration=c.fx.off?0:typeof f.duration===
+"number"?f.duration:c.fx.speeds[f.duration]||c.fx.speeds._default;f.old=f.complete;f.complete=function(){f.queue!==false&&c(this).dequeue();c.isFunction(f.old)&&f.old.call(this)};return f},easing:{linear:function(a,b,d,f){return d+f*a},swing:function(a,b,d,f){return(-Math.cos(a*Math.PI)/2+0.5)*f+d}},timers:[],fx:function(a,b,d){this.options=b;this.elem=a;this.prop=d;if(!b.orig)b.orig={}}});c.fx.prototype={update:function(){this.options.step&&this.options.step.call(this.elem,this.now,this);(c.fx.step[this.prop]||
+c.fx.step._default)(this);if((this.prop==="height"||this.prop==="width")&&this.elem.style)this.elem.style.display="block"},cur:function(a){if(this.elem[this.prop]!=null&&(!this.elem.style||this.elem.style[this.prop]==null))return this.elem[this.prop];return(a=parseFloat(c.css(this.elem,this.prop,a)))&&a>-10000?a:parseFloat(c.curCSS(this.elem,this.prop))||0},custom:function(a,b,d){function f(j){return e.step(j)}this.startTime=J();this.start=a;this.end=b;this.unit=d||this.unit||"px";this.now=this.start;
+this.pos=this.state=0;var e=this;f.elem=this.elem;if(f()&&c.timers.push(f)&&!W)W=setInterval(c.fx.tick,13)},show:function(){this.options.orig[this.prop]=c.style(this.elem,this.prop);this.options.show=true;this.custom(this.prop==="width"||this.prop==="height"?1:0,this.cur());c(this.elem).show()},hide:function(){this.options.orig[this.prop]=c.style(this.elem,this.prop);this.options.hide=true;this.custom(this.cur(),0)},step:function(a){var b=J(),d=true;if(a||b>=this.options.duration+this.startTime){this.now=
+this.end;this.pos=this.state=1;this.update();this.options.curAnim[this.prop]=true;for(var f in this.options.curAnim)if(this.options.curAnim[f]!==true)d=false;if(d){if(this.options.display!=null){this.elem.style.overflow=this.options.overflow;a=c.data(this.elem,"olddisplay");this.elem.style.display=a?a:this.options.display;if(c.css(this.elem,"display")==="none")this.elem.style.display="block"}this.options.hide&&c(this.elem).hide();if(this.options.hide||this.options.show)for(var e in this.options.curAnim)c.style(this.elem,
+e,this.options.orig[e]);this.options.complete.call(this.elem)}return false}else{e=b-this.startTime;this.state=e/this.options.duration;a=this.options.easing||(c.easing.swing?"swing":"linear");this.pos=c.easing[this.options.specialEasing&&this.options.specialEasing[this.prop]||a](this.state,e,0,1,this.options.duration);this.now=this.start+(this.end-this.start)*this.pos;this.update()}return true}};c.extend(c.fx,{tick:function(){for(var a=c.timers,b=0;b<a.length;b++)a[b]()||a.splice(b--,1);a.length||
+c.fx.stop()},stop:function(){clearInterval(W);W=null},speeds:{slow:600,fast:200,_default:400},step:{opacity:function(a){c.style(a.elem,"opacity",a.now)},_default:function(a){if(a.elem.style&&a.elem.style[a.prop]!=null)a.elem.style[a.prop]=(a.prop==="width"||a.prop==="height"?Math.max(0,a.now):a.now)+a.unit;else a.elem[a.prop]=a.now}}});if(c.expr&&c.expr.filters)c.expr.filters.animated=function(a){return c.grep(c.timers,function(b){return a===b.elem}).length};c.fn.offset="getBoundingClientRect"in s.documentElement?
+function(a){var b=this[0];if(a)return this.each(function(e){c.offset.setOffset(this,a,e)});if(!b||!b.ownerDocument)return null;if(b===b.ownerDocument.body)return c.offset.bodyOffset(b);var d=b.getBoundingClientRect(),f=b.ownerDocument;b=f.body;f=f.documentElement;return{top:d.top+(self.pageYOffset||c.support.boxModel&&f.scrollTop||b.scrollTop)-(f.clientTop||b.clientTop||0),left:d.left+(self.pageXOffset||c.support.boxModel&&f.scrollLeft||b.scrollLeft)-(f.clientLeft||b.clientLeft||0)}}:function(a){var b=
+this[0];if(a)return this.each(function(r){c.offset.setOffset(this,a,r)});if(!b||!b.ownerDocument)return null;if(b===b.ownerDocument.body)return c.offset.bodyOffset(b);c.offset.initialize();var d=b.offsetParent,f=b,e=b.ownerDocument,j,i=e.documentElement,o=e.body;f=(e=e.defaultView)?e.getComputedStyle(b,null):b.currentStyle;for(var k=b.offsetTop,n=b.offsetLeft;(b=b.parentNode)&&b!==o&&b!==i;){if(c.offset.supportsFixedPosition&&f.position==="fixed")break;j=e?e.getComputedStyle(b,null):b.currentStyle;
+k-=b.scrollTop;n-=b.scrollLeft;if(b===d){k+=b.offsetTop;n+=b.offsetLeft;if(c.offset.doesNotAddBorder&&!(c.offset.doesAddBorderForTableAndCells&&/^t(able|d|h)$/i.test(b.nodeName))){k+=parseFloat(j.borderTopWidth)||0;n+=parseFloat(j.borderLeftWidth)||0}f=d;d=b.offsetParent}if(c.offset.subtractsBorderForOverflowNotVisible&&j.overflow!=="visible"){k+=parseFloat(j.borderTopWidth)||0;n+=parseFloat(j.borderLeftWidth)||0}f=j}if(f.position==="relative"||f.position==="static"){k+=o.offsetTop;n+=o.offsetLeft}if(c.offset.supportsFixedPosition&&
+f.position==="fixed"){k+=Math.max(i.scrollTop,o.scrollTop);n+=Math.max(i.scrollLeft,o.scrollLeft)}return{top:k,left:n}};c.offset={initialize:function(){var a=s.body,b=s.createElement("div"),d,f,e,j=parseFloat(c.curCSS(a,"marginTop",true))||0;c.extend(b.style,{position:"absolute",top:0,left:0,margin:0,border:0,width:"1px",height:"1px",visibility:"hidden"});b.innerHTML="<div style='position:absolute;top:0;left:0;margin:0;border:5px solid #000;padding:0;width:1px;height:1px;'><div></div></div><table style='position:absolute;top:0;left:0;margin:0;border:5px solid #000;padding:0;width:1px;height:1px;' cellpadding='0' cellspacing='0'><tr><td></td></tr></table>";
+a.insertBefore(b,a.firstChild);d=b.firstChild;f=d.firstChild;e=d.nextSibling.firstChild.firstChild;this.doesNotAddBorder=f.offsetTop!==5;this.doesAddBorderForTableAndCells=e.offsetTop===5;f.style.position="fixed";f.style.top="20px";this.supportsFixedPosition=f.offsetTop===20||f.offsetTop===15;f.style.position=f.style.top="";d.style.overflow="hidden";d.style.position="relative";this.subtractsBorderForOverflowNotVisible=f.offsetTop===-5;this.doesNotIncludeMarginInBodyOffset=a.offsetTop!==j;a.removeChild(b);
+c.offset.initialize=c.noop},bodyOffset:function(a){var b=a.offsetTop,d=a.offsetLeft;c.offset.initialize();if(c.offset.doesNotIncludeMarginInBodyOffset){b+=parseFloat(c.curCSS(a,"marginTop",true))||0;d+=parseFloat(c.curCSS(a,"marginLeft",true))||0}return{top:b,left:d}},setOffset:function(a,b,d){if(/static/.test(c.curCSS(a,"position")))a.style.position="relative";var f=c(a),e=f.offset(),j=parseInt(c.curCSS(a,"top",true),10)||0,i=parseInt(c.curCSS(a,"left",true),10)||0;if(c.isFunction(b))b=b.call(a,
+d,e);d={top:b.top-e.top+j,left:b.left-e.left+i};"using"in b?b.using.call(a,d):f.css(d)}};c.fn.extend({position:function(){if(!this[0])return null;var a=this[0],b=this.offsetParent(),d=this.offset(),f=/^body|html$/i.test(b[0].nodeName)?{top:0,left:0}:b.offset();d.top-=parseFloat(c.curCSS(a,"marginTop",true))||0;d.left-=parseFloat(c.curCSS(a,"marginLeft",true))||0;f.top+=parseFloat(c.curCSS(b[0],"borderTopWidth",true))||0;f.left+=parseFloat(c.curCSS(b[0],"borderLeftWidth",true))||0;return{top:d.top-
+f.top,left:d.left-f.left}},offsetParent:function(){return this.map(function(){for(var a=this.offsetParent||s.body;a&&!/^body|html$/i.test(a.nodeName)&&c.css(a,"position")==="static";)a=a.offsetParent;return a})}});c.each(["Left","Top"],function(a,b){var d="scroll"+b;c.fn[d]=function(f){var e=this[0],j;if(!e)return null;if(f!==w)return this.each(function(){if(j=wa(this))j.scrollTo(!a?f:c(j).scrollLeft(),a?f:c(j).scrollTop());else this[d]=f});else return(j=wa(e))?"pageXOffset"in j?j[a?"pageYOffset":
+"pageXOffset"]:c.support.boxModel&&j.document.documentElement[d]||j.document.body[d]:e[d]}});c.each(["Height","Width"],function(a,b){var d=b.toLowerCase();c.fn["inner"+b]=function(){return this[0]?c.css(this[0],d,false,"padding"):null};c.fn["outer"+b]=function(f){return this[0]?c.css(this[0],d,false,f?"margin":"border"):null};c.fn[d]=function(f){var e=this[0];if(!e)return f==null?null:this;if(c.isFunction(f))return this.each(function(j){var i=c(this);i[d](f.call(this,j,i[d]()))});return"scrollTo"in
+e&&e.document?e.document.compatMode==="CSS1Compat"&&e.document.documentElement["client"+b]||e.document.body["client"+b]:e.nodeType===9?Math.max(e.documentElement["client"+b],e.body["scroll"+b],e.documentElement["scroll"+b],e.body["offset"+b],e.documentElement["offset"+b]):f===w?c.css(e,d):this.css(d,typeof f==="string"?f:f+"px")}});A.jQuery=A.$=c})(window);
diff --git a/www/js/jstree-1.0-rc2/jquery.jstree.js b/www/js/jstree-1.0-rc2/jquery.jstree.js
new file mode 100644
index 0000000..bbfc355
--- /dev/null
+++ b/www/js/jstree-1.0-rc2/jquery.jstree.js
@@ -0,0 +1,3510 @@
+/*
+ * jsTree 1.0-rc1
+ * http://jstree.com/
+ *
+ * Copyright (c) 2010 Ivan Bozhanov (vakata.com)
+ *
+ * Dual licensed under the MIT and GPL licenses (same as jQuery):
+ * http://www.opensource.org/licenses/mit-license.php
+ * http://www.gnu.org/licenses/gpl.html
+ *
+ * $Date: 2010-07-01 10:51:11 +0300 (четв, 01 юли 2010) $
+ * $Revision: 191 $
+ */
+
+/*jslint browser: true, onevar: true, undef: true, bitwise: true, strict: true */
+/*global window : false, clearInterval: false, clearTimeout: false, document: false, setInterval: false, setTimeout: false, jQuery: false, navigator: false, XSLTProcessor: false, DOMParser: false, XMLSerializer: false*/
+
+"use strict";
+// Common functions not related to jsTree
+// decided to move them to a `vakata` "namespace"
+(function ($) {
+ $.vakata = {};
+ // CSS related functions
+ $.vakata.css = {
+ get_css : function(rule_name, delete_flag, sheet) {
+ rule_name = rule_name.toLowerCase();
+ var css_rules = sheet.cssRules || sheet.rules,
+ j = 0;
+ do {
+ if(css_rules.length && j > css_rules.length + 5) { return false; }
+ if(css_rules[j].selectorText && css_rules[j].selectorText.toLowerCase() == rule_name) {
+ if(delete_flag === true) {
+ if(sheet.removeRule) { sheet.removeRule(j); }
+ if(sheet.deleteRule) { sheet.deleteRule(j); }
+ return true;
+ }
+ else { return css_rules[j]; }
+ }
+ }
+ while (css_rules[++j]);
+ return false;
+ },
+ add_css : function(rule_name, sheet) {
+ if($.jstree.css.get_css(rule_name, false, sheet)) { return false; }
+ if(sheet.insertRule) { sheet.insertRule(rule_name + ' { }', 0); } else { sheet.addRule(rule_name, null, 0); }
+ return $.vakata.css.get_css(rule_name);
+ },
+ remove_css : function(rule_name, sheet) {
+ return $.vakata.css.get_css(rule_name, true, sheet);
+ },
+ add_sheet : function(opts) {
+ var tmp;
+ if(opts.str) {
+ tmp = document.createElement("style");
+ tmp.setAttribute('type',"text/css");
+ if(tmp.styleSheet) {
+ document.getElementsByTagName("head")[0].appendChild(tmp);
+ tmp.styleSheet.cssText = opts.str;
+ }
+ else {
+ tmp.appendChild(document.createTextNode(opts.str));
+ document.getElementsByTagName("head")[0].appendChild(tmp);
+ }
+ return tmp.sheet || tmp.styleSheet;
+ }
+ if(opts.url) {
+ if(document.createStyleSheet) {
+ try { tmp = document.createStyleSheet(opts.url); } catch (e) { }
+ }
+ else {
+ tmp = document.createElement('link');
+ tmp.rel = 'stylesheet';
+ tmp.type = 'text/css';
+ tmp.media = "all";
+ tmp.href = opts.url;
+ document.getElementsByTagName("head")[0].appendChild(tmp);
+ return tmp.styleSheet;
+ }
+ }
+ }
+ };
+})(jQuery);
+
+/*
+ * jsTree core 1.0
+ */
+(function ($) {
+ // private variables
+ var instances = [], // instance array (used by $.jstree.reference/create/focused)
+ focused_instance = -1, // the index in the instance array of the currently focused instance
+ plugins = {}, // list of included plugins
+ prepared_move = {}, // for the move plugin
+ is_ie6 = false;
+
+ // jQuery plugin wrapper (thanks to jquery UI widget function)
+ $.fn.jstree = function (settings) {
+ var isMethodCall = (typeof settings == 'string'), // is this a method call like $().jstree("open_node")
+ args = Array.prototype.slice.call(arguments, 1),
+ returnValue = this;
+
+ // extend settings and allow for multiple hashes and metadata
+ if(!isMethodCall && $.meta) { args.push($.metadata.get(this).jstree); }
+ settings = !isMethodCall && args.length ? $.extend.apply(null, [true, settings].concat(args)) : settings;
+ // block calls to "private" methods
+ if(isMethodCall && settings.substring(0, 1) == '_') { return returnValue; }
+
+ // if a method call execute the method on all selected instances
+ if(isMethodCall) {
+ this.each(function() {
+ var instance = instances[$.data(this, "jstree-instance-id")],
+ methodValue = (instance && $.isFunction(instance[settings])) ? instance[settings].apply(instance, args) : instance;
+ if(typeof methodValue !== "undefined" && (settings.indexOf("is_" === 0) || (methodValue !== true && methodValue !== false))) { returnValue = methodValue; return false; }
+ });
+ }
+ else {
+ this.each(function() {
+ var instance_id = $.data(this, "jstree-instance-id"),
+ s = false;
+ // if an instance already exists, destroy it first
+ if(typeof instance_id !== "undefined" && instances[instance_id]) { instances[instance_id].destroy(); }
+ // push a new empty object to the instances array
+ instance_id = parseInt(instances.push({}),10) - 1;
+ // store the jstree instance id to the container element
+ $.data(this, "jstree-instance-id", instance_id);
+ // clean up all plugins
+ if(!settings) { settings = {}; }
+ settings.plugins = $.isArray(settings.plugins) ? settings.plugins : $.jstree.defaults.plugins;
+ if($.inArray("core", settings.plugins) === -1) { settings.plugins.unshift("core"); }
+
+ // only unique plugins (NOT WORKING)
+ // settings.plugins = settings.plugins.sort().join(",,").replace(/(,|^)([^,]+)(,,\2)+(,|$)/g,"$1$2$4").replace(/,,+/g,",").replace(/,$/,"").split(",");
+
+ // extend defaults with passed data
+ s = $.extend(true, {}, $.jstree.defaults, settings);
+ s.plugins = settings.plugins;
+ $.each(plugins, function (i, val) { if($.inArray(i, s.plugins) === -1) { s[i] = null; delete s[i]; } });
+ // push the new object to the instances array (at the same time set the default classes to the container) and init
+ instances[instance_id] = new $.jstree._instance(instance_id, $(this).addClass("jstree jstree-" + instance_id), s);
+ // init all activated plugins for this instance
+ $.each(instances[instance_id]._get_settings().plugins, function (i, val) { instances[instance_id].data[val] = {}; });
+ $.each(instances[instance_id]._get_settings().plugins, function (i, val) { if(plugins[val]) { plugins[val].__init.apply(instances[instance_id]); } });
+ // initialize the instance
+ instances[instance_id].init();
+ });
+ }
+ // return the jquery selection (or if it was a method call that returned a value - the returned value)
+ return returnValue;
+ };
+ // object to store exposed functions and objects
+ $.jstree = {
+ defaults : {
+ plugins : []
+ },
+ _focused : function () { return instances[focused_instance] || null; },
+ _reference : function (needle) {
+ // get by instance id
+ if(instances[needle]) { return instances[needle]; }
+ // get by DOM (if still no luck - return null
+ var o = $(needle);
+ if(!o.length && typeof needle === "string") { o = $("#" + needle); }
+ if(!o.length) { return null; }
+ return instances[o.closest(".jstree").data("jstree-instance-id")] || null;
+ },
+ _instance : function (index, container, settings) {
+ // for plugins to store data in
+ this.data = { core : {} };
+ this.get_settings = function () { return $.extend(true, {}, settings); };
+ this._get_settings = function () { return settings; };
+ this.get_index = function () { return index; };
+ this.get_container = function () { return container; };
+ this._set_settings = function (s) {
+ settings = $.extend(true, {}, settings, s);
+ };
+ },
+ _fn : { },
+ plugin : function (pname, pdata) {
+ pdata = $.extend({}, {
+ __init : $.noop,
+ __destroy : $.noop,
+ _fn : {},
+ defaults : false
+ }, pdata);
+ plugins[pname] = pdata;
+
+ $.jstree.defaults[pname] = pdata.defaults;
+ $.each(pdata._fn, function (i, val) {
+ val.plugin = pname;
+ val.old = $.jstree._fn[i];
+ $.jstree._fn[i] = function () {
+ var rslt,
+ func = val,
+ args = Array.prototype.slice.call(arguments),
+ evnt = new $.Event("before.jstree"),
+ rlbk = false;
+
+ // Check if function belongs to the included plugins of this instance
+ do {
+ if(func && func.plugin && $.inArray(func.plugin, this._get_settings().plugins) !== -1) { break; }
+ func = func.old;
+ } while(func);
+ if(!func) { return; }
+
+ // a chance to stop execution (or change arguments):
+ // * just bind to jstree.before
+ // * check the additional data object (func property)
+ // * call event.stopImmediatePropagation()
+ // * return false (or an array of arguments)
+ rslt = this.get_container().triggerHandler(evnt, { "func" : i, "inst" : this, "args" : args });
+ if(rslt === false) { return; }
+ if(typeof rslt !== "undefined") { args = rslt; }
+
+ // context and function to trigger events, then finally call the function
+ if(i.indexOf("_") === 0) {
+ rslt = func.apply(this, args);
+ }
+ else {
+ rslt = func.apply(
+ $.extend({}, this, {
+ __callback : function (data) {
+ this.get_container().triggerHandler( i + '.jstree', { "inst" : this, "args" : args, "rslt" : data, "rlbk" : rlbk });
+ },
+ __rollback : function () {
+ rlbk = this.get_rollback();
+ return rlbk;
+ },
+ __call_old : function (replace_arguments) {
+ return func.old.apply(this, (replace_arguments ? Array.prototype.slice.call(arguments, 1) : args ) );
+ }
+ }), args);
+ }
+
+ // return the result
+ return rslt;
+ };
+ $.jstree._fn[i].old = val.old;
+ $.jstree._fn[i].plugin = pname;
+ });
+ },
+ rollback : function (rb) {
+ if(rb) {
+ if(!$.isArray(rb)) { rb = [ rb ]; }
+ $.each(rb, function (i, val) {
+ instances[val.i].set_rollback(val.h, val.d);
+ });
+ }
+ }
+ };
+ // set the prototype for all instances
+ $.jstree._fn = $.jstree._instance.prototype = {};
+
+ // css functions - used internally
+
+ // load the css when DOM is ready
+ $(function() {
+ // code is copied form jQuery ($.browser is deprecated + there is a bug in IE)
+ var u = navigator.userAgent.toLowerCase(),
+ v = (u.match( /.+?(?:rv|it|ra|ie)[\/: ]([\d.]+)/ ) || [0,'0'])[1],
+ css_string = '' +
+ '.jstree ul, .jstree li { display:block; margin:0 0 0 0; padding:0 0 0 0; list-style-type:none; } ' +
+ '.jstree li { display:block; min-height:18px; line-height:18px; white-space:nowrap; margin-left:18px; } ' +
+ '.jstree-rtl li { margin-left:0; margin-right:18px; } ' +
+ '.jstree > ul > li { margin-left:0px; } ' +
+ '.jstree-rtl > ul > li { margin-right:0px; } ' +
+ '.jstree ins { display:inline-block; text-decoration:none; width:18px; height:18px; margin:0 0 0 0; padding:0; } ' +
+ '.jstree a { display:inline-block; line-height:16px; height:16px; color:black; white-space:nowrap; text-decoration:none; padding:1px 2px; margin:0; } ' +
+ '.jstree a:focus { outline: none; } ' +
+ '.jstree a > ins { height:16px; width:16px; } ' +
+ '.jstree a > .jstree-icon { margin-right:3px; } ' +
+ '.jstree-rtl a > .jstree-icon { margin-left:3px; margin-right:0; } ' +
+ 'li.jstree-open > ul { display:block; } ' +
+ 'li.jstree-closed > ul { display:none; } ';
+ // Correct IE 6 (does not support the > CSS selector)
+ if(/msie/.test(u) && parseInt(v, 10) == 6) {
+ is_ie6 = true;
+ css_string += '' +
+ '.jstree li { height:18px; margin-left:0; margin-right:0; } ' +
+ '.jstree li li { margin-left:18px; } ' +
+ '.jstree-rtl li li { margin-left:0px; margin-right:18px; } ' +
+ 'li.jstree-open ul { display:block; } ' +
+ 'li.jstree-closed ul { display:none !important; } ' +
+ '.jstree li a { display:inline; border-width:0 !important; padding:0px 2px !important; } ' +
+ '.jstree li a ins { height:16px; width:16px; margin-right:3px; } ' +
+ '.jstree-rtl li a ins { margin-right:0px; margin-left:3px; } ';
+ }
+ // Correct IE 7 (shifts anchor nodes onhover)
+ if(/msie/.test(u) && parseInt(v, 10) == 7) {
+ css_string += '.jstree li a { border-width:0 !important; padding:0px 2px !important; } ';
+ }
+ $.vakata.css.add_sheet({ str : css_string });
+ });
+
+ // core functions (open, close, create, update, delete)
+ $.jstree.plugin("core", {
+ __init : function () {
+ this.data.core.to_open = $.map($.makeArray(this.get_settings().core.initially_open), function (n) { return "#" + n.toString().replace(/^#/,"").replace('\\/','/').replace('/','\\/'); });
+ },
+ defaults : {
+ html_titles : false,
+ animation : 500,
+ initially_open : [],
+ rtl : false,
+ strings : {
+ loading : "Loading ...",
+ new_node : "New node"
+ }
+ },
+ _fn : {
+ init : function () {
+ this.set_focus();
+ if(this._get_settings().core.rtl) {
+ this.get_container().addClass("jstree-rtl").css("direction", "rtl");
+ }
+ this.get_container().html("<ul><li class='jstree-last jstree-leaf'><ins>&#160;</ins><a class='jstree-loading' href='#'><ins class='jstree-icon'>&#160;</ins>" + this._get_settings().core.strings.loading + "</a></li></ul>");
+ this.data.core.li_height = this.get_container().find("ul li.jstree-closed, ul li.jstree-leaf").eq(0).height() || 18;
+
+ this.get_container()
+ .delegate("li > ins", "click.jstree", $.proxy(function (event) {
+ var trgt = $(event.target);
+ if(trgt.is("ins") && event.pageY - trgt.offset().top < this.data.core.li_height) { this.toggle_node(trgt); }
+ }, this))
+ .bind("mousedown.jstree", $.proxy(function () {
+ this.set_focus(); // This used to be setTimeout(set_focus,0) - why?
+ }, this))
+ .bind("dblclick.jstree", function (event) {
+ var sel;
+ if(document.selection && document.selection.empty) { document.selection.empty(); }
+ else {
+ if(window.getSelection) {
+ sel = window.getSelection();
+ try {
+ sel.removeAllRanges();
+ sel.collapse();
+ } catch (err) { }
+ }
+ }
+ });
+ this.__callback();
+ this.load_node(-1, function () { this.loaded(); this.reopen(); });
+ },
+ destroy : function () {
+ var i,
+ n = this.get_index(),
+ s = this._get_settings(),
+ _this = this;
+
+ $.each(s.plugins, function (i, val) {
+ try { plugins[val].__destroy.apply(_this); } catch(err) { }
+ });
+ this.__callback();
+ // set focus to another instance if this one is focused
+ if(this.is_focused()) {
+ for(i in instances) {
+ if(instances.hasOwnProperty(i) && i != n) {
+ instances[i].set_focus();
+ break;
+ }
+ }
+ }
+ // if no other instance found
+ if(n === focused_instance) { focused_instance = -1; }
+ // remove all traces of jstree in the DOM (only the ones set using jstree*) and cleans all events
+ this.get_container()
+ .unbind(".jstree")
+ .undelegate(".jstree")
+ .removeData("jstree-instance-id")
+ .find("[class^='jstree']")
+ .andSelf()
+ .attr("class", function () { return this.className.replace(/jstree[^ ]*|$/ig,''); });
+ // remove the actual data
+ instances[n] = null;
+ delete instances[n];
+ },
+ save_opened : function () {
+ var _this = this;
+ this.data.core.to_open = [];
+ this.get_container().find(".jstree-open").each(function () {
+ _this.data.core.to_open.push("#" + this.id.toString().replace(/^#/,"").replace('\\/','/').replace('/','\\/'));
+ });
+ this.__callback(_this.data.core.to_open);
+ },
+ reopen : function (is_callback) {
+ var _this = this,
+ done = true,
+ current = [],
+ remaining = [];
+ if(!is_callback) { this.data.core.reopen = false; this.data.core.refreshing = true; }
+ if(this.data.core.to_open.length) {
+ $.each(this.data.core.to_open, function (i, val) {
+ if(val == "#") { return true; }
+ if($(val).length && $(val).is(".jstree-closed")) { current.push(val); }
+ else { remaining.push(val); }
+ });
+ if(current.length) {
+ this.data.core.to_open = remaining;
+ $.each(current, function (i, val) {
+ _this.open_node(val, function () { _this.reopen(true); }, true);
+ });
+ done = false;
+ }
+ }
+ if(done) {
+ // TODO: find a more elegant approach to syncronizing returning requests
+ if(this.data.core.reopen) { clearTimeout(this.data.core.reopen); }
+ this.data.core.reopen = setTimeout(function () { _this.__callback({}, _this); }, 50);
+ this.data.core.refreshing = false;
+ }
+ },
+ refresh : function (obj) {
+ var _this = this;
+ this.save_opened();
+ if(!obj) { obj = -1; }
+ obj = this._get_node(obj);
+ if(!obj) { obj = -1; }
+ if(obj !== -1) { obj.children("UL").remove(); }
+ this.load_node(obj, function () { _this.__callback({ "obj" : obj}); _this.reopen(); });
+ },
+ // Dummy function to fire after the first load (so that there is a jstree.loaded event)
+ loaded : function () {
+ this.__callback();
+ },
+ // deal with focus
+ set_focus : function () {
+ var f = $.jstree._focused();
+ if(f && f !== this) {
+ f.get_container().removeClass("jstree-focused");
+ }
+ if(f !== this) {
+ this.get_container().addClass("jstree-focused");
+ focused_instance = this.get_index();
+ }
+ this.__callback();
+ },
+ is_focused : function () {
+ return focused_instance == this.get_index();
+ },
+
+ // traverse
+ _get_node : function (obj) {
+ var $obj = $(obj, this.get_container());
+ if($obj.is(".jstree") || obj == -1) { return -1; }
+ $obj = $obj.closest("li", this.get_container());
+ return $obj.length ? $obj : false;
+ },
+ _get_next : function (obj, strict) {
+ obj = this._get_node(obj);
+ if(obj === -1) { return this.get_container().find("> ul > li:first-child"); }
+ if(!obj.length) { return false; }
+ if(strict) { return (obj.nextAll("li").size() > 0) ? obj.nextAll("li:eq(0)") : false; }
+
+ if(obj.hasClass("jstree-open")) { return obj.find("li:eq(0)"); }
+ else if(obj.nextAll("li").size() > 0) { return obj.nextAll("li:eq(0)"); }
+ else { return obj.parentsUntil(".jstree","li").next("li").eq(0); }
+ },
+ _get_prev : function (obj, strict) {
+ obj = this._get_node(obj);
+ if(obj === -1) { return this.get_container().find("> ul > li:last-child"); }
+ if(!obj.length) { return false; }
+ if(strict) { return (obj.prevAll("li").length > 0) ? obj.prevAll("li:eq(0)") : false; }
+
+ if(obj.prev("li").length) {
+ obj = obj.prev("li").eq(0);
+ while(obj.hasClass("jstree-open")) { obj = obj.children("ul:eq(0)").children("li:last"); }
+ return obj;
+ }
+ else { var o = obj.parentsUntil(".jstree","li:eq(0)"); return o.length ? o : false; }
+ },
+ _get_parent : function (obj) {
+ obj = this._get_node(obj);
+ if(obj == -1 || !obj.length) { return false; }
+ var o = obj.parentsUntil(".jstree", "li:eq(0)");
+ return o.length ? o : -1;
+ },
+ _get_children : function (obj) {
+ obj = this._get_node(obj);
+ if(obj === -1) { return this.get_container().children("ul:eq(0)").children("li"); }
+ if(!obj.length) { return false; }
+ return obj.children("ul:eq(0)").children("li");
+ },
+ get_path : function (obj, id_mode) {
+ var p = [],
+ _this = this;
+ obj = this._get_node(obj);
+ if(obj === -1 || !obj || !obj.length) { return false; }
+ obj.parentsUntil(".jstree", "li").each(function () {
+ p.push( id_mode ? this.id : _this.get_text(this) );
+ });
+ p.reverse();
+ p.push( id_mode ? obj.attr("id") : this.get_text(obj) );
+ return p;
+ },
+
+ is_open : function (obj) { obj = this._get_node(obj); return obj && obj !== -1 && obj.hasClass("jstree-open"); },
+ is_closed : function (obj) { obj = this._get_node(obj); return obj && obj !== -1 && obj.hasClass("jstree-closed"); },
+ is_leaf : function (obj) { obj = this._get_node(obj); return obj && obj !== -1 && obj.hasClass("jstree-leaf"); },
+ // open/close
+ open_node : function (obj, callback, skip_animation) {
+ obj = this._get_node(obj);
+ if(!obj.length) { return false; }
+ if(!obj.hasClass("jstree-closed")) { if(callback) { callback.call(); } return false; }
+ var s = skip_animation || is_ie6 ? 0 : this._get_settings().core.animation,
+ t = this;
+ if(!this._is_loaded(obj)) {
+ obj.children("a").addClass("jstree-loading");
+ this.load_node(obj, function () { t.open_node(obj, callback, skip_animation); }, callback);
+ }
+ else {
+ if(s) { obj.children("ul").css("display","none"); }
+ obj.removeClass("jstree-closed").addClass("jstree-open").children("a").removeClass("jstree-loading");
+ if(s) { obj.children("ul").stop(true).slideDown(s, function () { this.style.display = ""; }); }
+ this.__callback({ "obj" : obj });
+ if(callback) { callback.call(); }
+ }
+ },
+ close_node : function (obj, skip_animation) {
+ obj = this._get_node(obj);
+ var s = skip_animation || is_ie6 ? 0 : this._get_settings().core.animation;
+ if(!obj.length || !obj.hasClass("jstree-open")) { return false; }
+ if(s) { obj.children("ul").attr("style","display:block !important"); }
+ obj.removeClass("jstree-open").addClass("jstree-closed");
+ if(s) { obj.children("ul").stop(true).slideUp(s, function () { this.style.display = ""; }); }
+ this.__callback({ "obj" : obj });
+ },
+ toggle_node : function (obj) {
+ obj = this._get_node(obj);
+ if(obj.hasClass("jstree-closed")) { return this.open_node(obj); }
+ if(obj.hasClass("jstree-open")) { return this.close_node(obj); }
+ },
+ open_all : function (obj, original_obj) {
+ obj = obj ? this._get_node(obj) : this.get_container();
+ if(!obj || obj === -1) { obj = this.get_container(); }
+ if(original_obj) {
+ obj = obj.find("li.jstree-closed");
+ }
+ else {
+ original_obj = obj;
+ if(obj.is(".jstree-closed")) { obj = obj.find("li.jstree-closed").andSelf(); }
+ else { obj = obj.find("li.jstree-closed"); }
+ }
+ var _this = this;
+ obj.each(function () {
+ var __this = this;
+ if(!_this._is_loaded(this)) { _this.open_node(this, function() { _this.open_all(__this, original_obj); }, true); }
+ else { _this.open_node(this, false, true); }
+ });
+ // so that callback is fired AFTER all nodes are open
+ if(original_obj.find('li.jstree-closed').length === 0) { this.__callback({ "obj" : original_obj }); }
+ },
+ close_all : function (obj) {
+ var _this = this;
+ obj = obj ? this._get_node(obj) : this.get_container();
+ if(!obj || obj === -1) { obj = this.get_container(); }
+ obj.find("li.jstree-open").andSelf().each(function () { _this.close_node(this); });
+ this.__callback({ "obj" : obj });
+ },
+ clean_node : function (obj) {
+ obj = obj && obj != -1 ? $(obj) : this.get_container();
+ obj = obj.is("li") ? obj.find("li").andSelf() : obj.find("li");
+ obj.removeClass("jstree-last")
+ .filter("li:last-child").addClass("jstree-last").end()
+ .filter(":has(li)")
+ .not(".jstree-open").removeClass("jstree-leaf").addClass("jstree-closed");
+ obj.not(".jstree-open, .jstree-closed").addClass("jstree-leaf").children("ul").remove();
+ this.__callback({ "obj" : obj });
+ },
+ // rollback
+ get_rollback : function () {
+ this.__callback();
+ return { i : this.get_index(), h : this.get_container().children("ul").clone(true), d : this.data };
+ },
+ set_rollback : function (html, data) {
+ this.get_container().empty().append(html);
+ this.data = data;
+ this.__callback();
+ },
+ // Dummy functions to be overwritten by any datastore plugin included
+ load_node : function (obj, s_call, e_call) { this.__callback({ "obj" : obj }); },
+ _is_loaded : function (obj) { return true; },
+
+ // Basic operations: create
+ create_node : function (obj, position, js, callback, is_loaded) {
+ obj = this._get_node(obj);
+ position = typeof position === "undefined" ? "last" : position;
+ var d = $("<li>"),
+ s = this._get_settings().core,
+ tmp;
+
+ if(obj !== -1 && !obj.length) { return false; }
+ if(!is_loaded && !this._is_loaded(obj)) { this.load_node(obj, function () { this.create_node(obj, position, js, callback, true); }); return false; }
+
+ this.__rollback();
+
+ if(typeof js === "string") { js = { "data" : js }; }
+ if(!js) { js = {}; }
+ if(js.attr) { d.attr(js.attr); }
+ if(js.state) { d.addClass("jstree-" + js.state); }
+ if(!js.data) { js.data = s.strings.new_node; }
+ if(!$.isArray(js.data)) { tmp = js.data; js.data = []; js.data.push(tmp); }
+ $.each(js.data, function (i, m) {
+ tmp = $("<a>");
+ if($.isFunction(m)) { m = m.call(this, js); }
+ if(typeof m == "string") { tmp.attr('href','#')[ s.html_titles ? "html" : "text" ](m); }
+ else {
+ if(!m.attr) { m.attr = {}; }
+ if(!m.attr.href) { m.attr.href = '#'; }
+ tmp.attr(m.attr)[ s.html_titles ? "html" : "text" ](m.title);
+ if(m.language) { tmp.addClass(m.language); }
+ }
+ tmp.prepend("<ins class='jstree-icon'>&#160;</ins>");
+ if(m.icon) {
+ if(m.icon.indexOf("/") === -1) { tmp.children("ins").addClass(m.icon); }
+ else { tmp.children("ins").css("background","url('" + m.icon + "') center center no-repeat"); }
+ }
+ d.append(tmp);
+ });
+ d.prepend("<ins class='jstree-icon'>&#160;</ins>");
+ if(obj === -1) {
+ obj = this.get_container();
+ if(position === "before") { position = "first"; }
+ if(position === "after") { position = "last"; }
+ }
+ switch(position) {
+ case "before": obj.before(d); tmp = this._get_parent(obj); break;
+ case "after" : obj.after(d); tmp = this._get_parent(obj); break;
+ case "inside":
+ case "first" :
+ if(!obj.children("ul").length) { obj.append("<ul>"); }
+ obj.children("ul").prepend(d);
+ tmp = obj;
+ break;
+ case "last":
+ if(!obj.children("ul").length) { obj.append("<ul>"); }
+ obj.children("ul").append(d);
+ tmp = obj;
+ break;
+ default:
+ if(!obj.children("ul").length) { obj.append("<ul>"); }
+ if(!position) { position = 0; }
+ tmp = obj.children("ul").children("li").eq(position);
+ if(tmp.length) { tmp.before(d); }
+ else { obj.children("ul").append(d); }
+ tmp = obj;
+ break;
+ }
+ if(tmp === -1 || tmp.get(0) === this.get_container().get(0)) { tmp = -1; }
+ this.clean_node(tmp);
+ this.__callback({ "obj" : d, "parent" : tmp });
+ if(callback) { callback.call(this, d); }
+ return d;
+ },
+ // Basic operations: rename (deal with text)
+ get_text : function (obj) {
+ obj = this._get_node(obj);
+ if(!obj.length) { return false; }
+ var s = this._get_settings().core.html_titles;
+ obj = obj.children("a:eq(0)");
+ if(s) {
+ obj = obj.clone();
+ obj.children("INS").remove();
+ return obj.html();
+ }
+ else {
+ obj = obj.contents().filter(function() { return this.nodeType == 3; })[0];
+ return obj.nodeValue;
+ }
+ },
+ set_text : function (obj, val) {
+ obj = this._get_node(obj);
+ if(!obj.length) { return false; }
+ obj = obj.children("a:eq(0)");
+ if(this._get_settings().core.html_titles) {
+ var tmp = obj.children("INS").clone();
+ obj.html(val).prepend(tmp);
+ this.__callback({ "obj" : obj, "name" : val });
+ return true;
+ }
+ else {
+ obj = obj.contents().filter(function() { return this.nodeType == 3; })[0];
+ this.__callback({ "obj" : obj, "name" : val });
+ return (obj.nodeValue = val);
+ }
+ },
+ rename_node : function (obj, val) {
+ obj = this._get_node(obj);
+ this.__rollback();
+ if(obj && obj.length && this.set_text.apply(this, Array.prototype.slice.call(arguments))) { this.__callback({ "obj" : obj, "name" : val }); }
+ },
+ // Basic operations: deleting nodes
+ delete_node : function (obj) {
+ obj = this._get_node(obj);
+ if(!obj.length) { return false; }
+ this.__rollback();
+ var p = this._get_parent(obj), prev = this._get_prev(obj);
+ obj = obj.remove();
+ if(p !== -1 && p.find("> ul > li").length === 0) {
+ p.removeClass("jstree-open jstree-closed").addClass("jstree-leaf");
+ }
+ this.clean_node(p);
+ this.__callback({ "obj" : obj, "prev" : prev });
+ return obj;
+ },
+ prepare_move : function (o, r, pos, cb, is_cb) {
+ var p = {};
+
+ p.ot = $.jstree._reference(p.o) || this;
+ p.o = p.ot._get_node(o);
+ p.r = r === - 1 ? -1 : this._get_node(r);
+ p.p = (typeof p === "undefined") ? "last" : pos; // TODO: move to a setting
+ if(!is_cb && prepared_move.o && prepared_move.o[0] === p.o[0] && prepared_move.r[0] === p.r[0] && prepared_move.p === p.p) {
+ this.__callback(prepared_move);
+ if(cb) { cb.call(this, prepared_move); }
+ return;
+ }
+ p.ot = $.jstree._reference(p.o) || this;
+ p.rt = r === -1 ? p.ot : $.jstree._reference(p.r) || this;
+ if(p.r === -1) {
+ p.cr = -1;
+ switch(p.p) {
+ case "first":
+ case "before":
+ case "inside":
+ p.cp = 0;
+ break;
+ case "after":
+ case "last":
+ p.cp = p.rt.get_container().find(" > ul > li").length;
+ break;
+ default:
+ p.cp = p.p;
+ break;
+ }
+ }
+ else {
+ if(!/^(before|after)$/.test(p.p) && !this._is_loaded(p.r)) {
+ return this.load_node(p.r, function () { this.prepare_move(o, r, pos, cb, true); });
+ }
+ switch(p.p) {
+ case "before":
+ p.cp = p.r.index();
+ p.cr = p.rt._get_parent(p.r);
+ break;
+ case "after":
+ p.cp = p.r.index() + 1;
+ p.cr = p.rt._get_parent(p.r);
+ break;
+ case "inside":
+ case "first":
+ p.cp = 0;
+ p.cr = p.r;
+ break;
+ case "last":
+ p.cp = p.r.find(" > ul > li").length;
+ p.cr = p.r;
+ break;
+ default:
+ p.cp = p.p;
+ p.cr = p.r;
+ break;
+ }
+ }
+ p.np = p.cr == -1 ? p.rt.get_container() : p.cr;
+ p.op = p.ot._get_parent(p.o);
+ p.or = p.np.find(" > ul > li:nth-child(" + (p.cp + 1) + ")");
+
+ prepared_move = p;
+ this.__callback(prepared_move);
+ if(cb) { cb.call(this, prepared_move); }
+ },
+ check_move : function () {
+ var obj = prepared_move, ret = true;
+ if(obj.or[0] === obj.o[0]) { return false; }
+ obj.o.each(function () {
+ if(obj.r.parentsUntil(".jstree").andSelf().filter("li").index(this) !== -1) { ret = false; return false; }
+ });
+ return ret;
+ },
+ move_node : function (obj, ref, position, is_copy, is_prepared, skip_check) {
+ if(!is_prepared) {
+ return this.prepare_move(obj, ref, position, function (p) {
+ this.move_node(p, false, false, is_copy, true, skip_check);
+ });
+ }
+ if(!skip_check && !this.check_move()) { return false; }
+
+ this.__rollback();
+ var o = false;
+ if(is_copy) {
+ o = obj.o.clone();
+ o.find("*[id]").andSelf().each(function () {
+ if(this.id) { this.id = "copy_" + this.id; }
+ });
+ }
+ else { o = obj.o; }
+
+ if(obj.or.length) { obj.or.before(o); }
+ else {
+ if(!obj.np.children("ul").length) { $("<ul>").appendTo(obj.np); }
+ obj.np.children("ul:eq(0)").append(o);
+ }
+
+ try {
+ obj.ot.clean_node(obj.op);
+ obj.rt.clean_node(obj.np);
+ if(!obj.op.find("> ul > li").length) {
+ obj.op.removeClass("jstree-open jstree-closed").addClass("jstree-leaf").children("ul").remove();
+ }
+ } catch (e) { }
+
+ if(is_copy) {
+ prepared_move.cy = true;
+ prepared_move.oc = o;
+ }
+ this.__callback(prepared_move);
+ return prepared_move;
+ },
+ _get_move : function () { return prepared_move; }
+ }
+ });
+})(jQuery);
+//*/
+
+/*
+ * jsTree ui plugin 1.0
+ * This plugins handles selecting/deselecting/hovering/dehovering nodes
+ */
+(function ($) {
+ $.jstree.plugin("ui", {
+ __init : function () {
+ this.data.ui.selected = $();
+ this.data.ui.last_selected = false;
+ this.data.ui.hovered = null;
+ this.data.ui.to_select = this.get_settings().ui.initially_select;
+
+ this.get_container()
+ .delegate("a", "click.jstree", $.proxy(function (event) {
+ event.preventDefault();
+ this.select_node(event.currentTarget, true, event);
+ }, this))
+ .delegate("a", "mouseenter.jstree", $.proxy(function (event) {
+ this.hover_node(event.target);
+ }, this))
+ .delegate("a", "mouseleave.jstree", $.proxy(function (event) {
+ this.dehover_node(event.target);
+ }, this))
+ .bind("reopen.jstree", $.proxy(function () {
+ this.reselect();
+ }, this))
+ .bind("get_rollback.jstree", $.proxy(function () {
+ this.dehover_node();
+ this.save_selected();
+ }, this))
+ .bind("set_rollback.jstree", $.proxy(function () {
+ this.reselect();
+ }, this))
+ .bind("close_node.jstree", $.proxy(function (event, data) {
+ var s = this._get_settings().ui,
+ obj = this._get_node(data.rslt.obj),
+ clk = (obj && obj.length) ? obj.children("ul").find(".jstree-clicked") : $(),
+ _this = this;
+ if(s.selected_parent_close === false || !clk.length) { return; }
+ clk.each(function () {
+ _this.deselect_node(this);
+ if(s.selected_parent_close === "select_parent") { _this.select_node(obj); }
+ });
+ }, this))
+ .bind("delete_node.jstree", $.proxy(function (event, data) {
+ var s = this._get_settings().ui.select_prev_on_delete,
+ obj = this._get_node(data.rslt.obj),
+ clk = (obj && obj.length) ? obj.find(".jstree-clicked") : [],
+ _this = this;
+ clk.each(function () { _this.deselect_node(this); });
+ if(s && clk.length) { this.select_node(data.rslt.prev); }
+ }, this))
+ .bind("move_node.jstree", $.proxy(function (event, data) {
+ if(data.rslt.cy) {
+ data.rslt.oc.find(".jstree-clicked").removeClass("jstree-clicked");
+ }
+ }, this));
+ },
+ defaults : {
+ select_limit : -1, // 0, 1, 2 ... or -1 for unlimited
+ select_multiple_modifier : "ctrl", // on, or ctrl, shift, alt
+ selected_parent_close : "select_parent", // false, "deselect", "select_parent"
+ select_prev_on_delete : true,
+ disable_selecting_children : false,
+ initially_select : []
+ },
+ _fn : {
+ _get_node : function (obj, allow_multiple) {
+ if(typeof obj === "undefined" || obj === null) { return allow_multiple ? this.data.ui.selected : this.data.ui.last_selected; }
+ var $obj = $(obj, this.get_container());
+ if($obj.is(".jstree") || obj == -1) { return -1; }
+ $obj = $obj.closest("li", this.get_container());
+ return $obj.length ? $obj : false;
+ },
+ save_selected : function () {
+ var _this = this;
+ this.data.ui.to_select = [];
+ this.data.ui.selected.each(function () { _this.data.ui.to_select.push("#" + this.id.toString().replace(/^#/,"").replace('\\/','/').replace('/','\\/')); });
+ this.__callback(this.data.ui.to_select);
+ },
+ reselect : function () {
+ var _this = this,
+ s = this.data.ui.to_select;
+ s = $.map($.makeArray(s), function (n) { return "#" + n.toString().replace(/^#/,"").replace('\\/','/').replace('/','\\/'); });
+ this.deselect_all();
+ $.each(s, function (i, val) { if(val && val !== "#") { _this.select_node(val); } });
+ this.__callback();
+ },
+ refresh : function (obj) {
+ this.save_selected();
+ return this.__call_old();
+ },
+ hover_node : function (obj) {
+ obj = this._get_node(obj);
+ if(!obj.length) { return false; }
+ //if(this.data.ui.hovered && obj.get(0) === this.data.ui.hovered.get(0)) { return; }
+ if(!obj.hasClass("jstree-hovered")) { this.dehover_node(); }
+ this.data.ui.hovered = obj.children("a").addClass("jstree-hovered").parent();
+ this.__callback({ "obj" : obj });
+ },
+ dehover_node : function () {
+ var obj = this.data.ui.hovered, p;
+ if(!obj || !obj.length) { return false; }
+ p = obj.children("a").removeClass("jstree-hovered").parent();
+ if(this.data.ui.hovered[0] === p[0]) { this.data.ui.hovered = null; }
+ this.__callback({ "obj" : obj });
+ },
+ select_node : function (obj, check, e) {
+ obj = this._get_node(obj);
+ if(obj == -1 || !obj || !obj.length) { return false; }
+ var s = this._get_settings().ui,
+ is_multiple = (s.select_multiple_modifier == "on" || (s.select_multiple_modifier !== false && e && e[s.select_multiple_modifier + "Key"])),
+ is_selected = this.is_selected(obj),
+ proceed = true;
+ if(check) {
+ if(s.disable_selecting_children && is_multiple && obj.parents("li", this.get_container()).children(".jstree-clicked").length) {
+ return false;
+ }
+ proceed = false;
+ switch(!0) {
+ case (is_selected && !is_multiple):
+ this.deselect_all();
+ is_selected = false;
+ proceed = true;
+ break;
+ case (!is_selected && !is_multiple):
+ if(s.select_limit == -1 || s.select_limit > 0) {
+ this.deselect_all();
+ proceed = true;
+ }
+ break;
+ case (is_selected && is_multiple):
+ this.deselect_node(obj);
+ break;
+ case (!is_selected && is_multiple):
+ if(s.select_limit == -1 || this.data.ui.selected.length + 1 <= s.select_limit) {
+ proceed = true;
+ }
+ break;
+ }
+ }
+ if(proceed && !is_selected) {
+ obj.children("a").addClass("jstree-clicked");
+ this.data.ui.selected = this.data.ui.selected.add(obj);
+ this.data.ui.last_selected = obj;
+ this.__callback({ "obj" : obj });
+ }
+ },
+ deselect_node : function (obj) {
+ obj = this._get_node(obj);
+ if(!obj.length) { return false; }
+ if(this.is_selected(obj)) {
+ obj.children("a").removeClass("jstree-clicked");
+ this.data.ui.selected = this.data.ui.selected.not(obj);
+ if(this.data.ui.last_selected.get(0) === obj.get(0)) { this.data.ui.last_selected = this.data.ui.selected.eq(0); }
+ this.__callback({ "obj" : obj });
+ }
+ },
+ toggle_select : function (obj) {
+ obj = this._get_node(obj);
+ if(!obj.length) { return false; }
+ if(this.is_selected(obj)) { this.deselect_node(obj); }
+ else { this.select_node(obj); }
+ },
+ is_selected : function (obj) { return this.data.ui.selected.index(this._get_node(obj)) >= 0; },
+ get_selected : function (context) {
+ return context ? $(context).find(".jstree-clicked").parent() : this.data.ui.selected;
+ },
+ deselect_all : function (context) {
+ if(context) { $(context).find(".jstree-clicked").removeClass("jstree-clicked"); }
+ else { this.get_container().find(".jstree-clicked").removeClass("jstree-clicked"); }
+ this.data.ui.selected = $([]);
+ this.data.ui.last_selected = false;
+ this.__callback();
+ }
+ }
+ });
+ // include the selection plugin by default
+ $.jstree.defaults.plugins.push("ui");
+})(jQuery);
+//*/
+
+/*
+ * jsTree CRRM plugin 1.0
+ * Handles creating/renaming/removing/moving nodes by user interaction.
+ */
+(function ($) {
+ $.jstree.plugin("crrm", {
+ __init : function () {
+ this.get_container()
+ .bind("move_node.jstree", $.proxy(function (e, data) {
+ if(this._get_settings().crrm.move.open_onmove) {
+ var t = this;
+ data.rslt.np.parentsUntil(".jstree").andSelf().filter(".jstree-closed").each(function () {
+ t.open_node(this, false, true);
+ });
+ }
+ }, this));
+ },
+ defaults : {
+ input_width_limit : 200,
+ move : {
+ always_copy : false, // false, true or "multitree"
+ open_onmove : true,
+ default_position : "last",
+ check_move : function (m) { return true; }
+ }
+ },
+ _fn : {
+ _show_input : function (obj, callback) {
+ obj = this._get_node(obj);
+ var rtl = this._get_settings().core.rtl,
+ w = this._get_settings().crrm.input_width_limit,
+ w1 = obj.children("ins").width(),
+ w2 = obj.find("> a:visible > ins").width() * obj.find("> a:visible > ins").length,
+ t = this.get_text(obj),
+ h1 = $("<div>", { css : { "position" : "absolute", "top" : "-200px", "left" : (rtl ? "0px" : "-1000px"), "visibility" : "hidden" } }).appendTo("body"),
+ h2 = obj.css("position","relative").append(
+ $("<input>", {
+ "value" : t,
+ // "size" : t.length,
+ "css" : {
+ "padding" : "0",
+ "border" : "1px solid silver",
+ "position" : "absolute",
+ "left" : (rtl ? "auto" : (w1 + w2 + 4) + "px"),
+ "right" : (rtl ? (w1 + w2 + 4) + "px" : "auto"),
+ "top" : "0px",
+ "height" : (this.data.core.li_height - 2) + "px",
+ "lineHeight" : (this.data.core.li_height - 2) + "px",
+ "width" : "150px" // will be set a bit further down
+ },
+ "blur" : $.proxy(function () {
+ var i = obj.children("input"),
+ v = i.val();
+ if(v === "") { v = t; }
+ i.remove(); // rollback purposes
+ this.set_text(obj,t); // rollback purposes
+ this.rename_node(obj, v);
+ callback.call(this, obj, v, t);
+ obj.css("position","");
+ }, this),
+ "keyup" : function (event) {
+ var key = event.keyCode || event.which;
+ if(key == 27) { this.value = t; this.blur(); return; }
+ else if(key == 13) { this.blur(); return; }
+ else {
+ h2.width(Math.min(h1.text("pW" + this.value).width(),w));
+ }
+ }
+ })
+ ).children("input");
+ this.set_text(obj, "");
+ h1.css({
+ fontFamily : h2.css('fontFamily') || '',
+ fontSize : h2.css('fontSize') || '',
+ fontWeight : h2.css('fontWeight') || '',
+ fontStyle : h2.css('fontStyle') || '',
+ fontStretch : h2.css('fontStretch') || '',
+ fontVariant : h2.css('fontVariant') || '',
+ letterSpacing : h2.css('letterSpacing') || '',
+ wordSpacing : h2.css('wordSpacing') || ''
+ });
+ h2.width(Math.min(h1.text("pW" + h2[0].value).width(),w))[0].select();
+ },
+ rename : function (obj) {
+ obj = this._get_node(obj);
+ this.__rollback();
+ var f = this.__callback;
+ this._show_input(obj, function (obj, new_name, old_name) {
+ f.call(this, { "obj" : obj, "new_name" : new_name, "old_name" : old_name });
+ });
+ },
+ create : function (obj, position, js, callback, skip_rename) {
+ var t, _this = this;
+ obj = this._get_node(obj);
+ if(!obj) { obj = -1; }
+ this.__rollback();
+ t = this.create_node(obj, position, js, function (t) {
+ var p = this._get_parent(t),
+ pos = $(t).index();
+ if(callback) { callback.call(this, t); }
+ if(p.length && p.hasClass("jstree-closed")) { this.open_node(p, false, true); }
+ if(!skip_rename) {
+ this._show_input(t, function (obj, new_name, old_name) {
+ _this.__callback({ "obj" : obj, "name" : new_name, "parent" : p, "position" : pos });
+ });
+ }
+ else { _this.__callback({ "obj" : t, "name" : this.get_text(t), "parent" : p, "position" : pos }); }
+ });
+ return t;
+ },
+ remove : function (obj) {
+ obj = this._get_node(obj, true);
+ this.__rollback();
+ this.delete_node(obj);
+ this.__callback({ "obj" : obj });
+ },
+ check_move : function () {
+ if(!this.__call_old()) { return false; }
+ var s = this._get_settings().crrm.move;
+ if(!s.check_move.call(this, this._get_move())) { return false; }
+ return true;
+ },
+ move_node : function (obj, ref, position, is_copy, is_prepared, skip_check) {
+ var s = this._get_settings().crrm.move;
+ if(!is_prepared) {
+ if(!position) { position = s.default_position; }
+ if(position === "inside" && !s.default_position.match(/^(before|after)$/)) { position = s.default_position; }
+ return this.__call_old(true, obj, ref, position, is_copy, false, skip_check);
+ }
+ // if the move is already prepared
+ if(s.always_copy === true || (s.always_copy === "multitree" && obj.rt.get_index() !== obj.ot.get_index() )) {
+ is_copy = true;
+ }
+ this.__call_old(true, obj, ref, position, is_copy, true, skip_check);
+ },
+
+ cut : function (obj) {
+ obj = this._get_node(obj);
+ this.data.crrm.cp_nodes = false;
+ this.data.crrm.ct_nodes = false;
+ if(!obj || !obj.length) { return false; }
+ this.data.crrm.ct_nodes = obj;
+ },
+ copy : function (obj) {
+ obj = this._get_node(obj);
+ this.data.crrm.cp_nodes = false;
+ this.data.crrm.ct_nodes = false;
+ if(!obj || !obj.length) { return false; }
+ this.data.crrm.cp_nodes = obj;
+ },
+ paste : function (obj) {
+ obj = this._get_node(obj);
+ if(!obj || !obj.length) { return false; }
+ if(!this.data.crrm.ct_nodes && !this.data.crrm.cp_nodes) { return false; }
+ if(this.data.crrm.ct_nodes) { this.move_node(this.data.crrm.ct_nodes, obj); }
+ if(this.data.crrm.cp_nodes) { this.move_node(this.data.crrm.cp_nodes, obj, false, true); }
+ this.data.crrm.cp_nodes = false;
+ this.data.crrm.ct_nodes = false;
+ }
+ }
+ });
+ // include the crr plugin by default
+ $.jstree.defaults.plugins.push("crrm");
+})(jQuery);
+
+/*
+ * jsTree themes plugin 1.0
+ * Handles loading and setting themes, as well as detecting path to themes, etc.
+ */
+(function ($) {
+ var themes_loaded = [];
+ // this variable stores the path to the themes folder - if left as false - it will be autodetected
+ $.jstree._themes = false;
+ $.jstree.plugin("themes", {
+ __init : function () {
+ this.get_container()
+ .bind("init.jstree", $.proxy(function () {
+ var s = this._get_settings().themes;
+ this.data.themes.dots = s.dots;
+ this.data.themes.icons = s.icons;
+ //alert(s.dots);
+ this.set_theme(s.theme, s.url);
+ }, this))
+ .bind("loaded.jstree", $.proxy(function () {
+ // bound here too, as simple HTML tree's won't honor dots & icons otherwise
+ if(!this.data.themes.dots) { this.hide_dots(); }
+ else { this.show_dots(); }
+ if(!this.data.themes.icons) { this.hide_icons(); }
+ else { this.show_icons(); }
+ }, this));
+ },
+ defaults : {
+ theme : "default",
+ url : false,
+ dots : true,
+ icons : true
+ },
+ _fn : {
+ set_theme : function (theme_name, theme_url) {
+ if(!theme_name) { return false; }
+ if(!theme_url) { theme_url = $.jstree._themes + theme_name + '/style.css'; }
+ if($.inArray(theme_url, themes_loaded) == -1) {
+ $.vakata.css.add_sheet({ "url" : theme_url, "rel" : "jstree" });
+ themes_loaded.push(theme_url);
+ }
+ if(this.data.themes.theme != theme_name) {
+ this.get_container().removeClass('jstree-' + this.data.themes.theme);
+ this.data.themes.theme = theme_name;
+ }
+ this.get_container().addClass('jstree-' + theme_name);
+ if(!this.data.themes.dots) { this.hide_dots(); }
+ else { this.show_dots(); }
+ if(!this.data.themes.icons) { this.hide_icons(); }
+ else { this.show_icons(); }
+ this.__callback();
+ },
+ get_theme : function () { return this.data.themes.theme; },
+
+ show_dots : function () { this.data.themes.dots = true; this.get_container().children("ul").removeClass("jstree-no-dots"); },
+ hide_dots : function () { this.data.themes.dots = false; this.get_container().children("ul").addClass("jstree-no-dots"); },
+ toggle_dots : function () { if(this.data.themes.dots) { this.hide_dots(); } else { this.show_dots(); } },
+
+ show_icons : function () { this.data.themes.icons = true; this.get_container().children("ul").removeClass("jstree-no-icons"); },
+ hide_icons : function () { this.data.themes.icons = false; this.get_container().children("ul").addClass("jstree-no-icons"); },
+ toggle_icons: function () { if(this.data.themes.icons) { this.hide_icons(); } else { this.show_icons(); } }
+ }
+ });
+ // autodetect themes path
+ $(function () {
+ if($.jstree._themes === false) {
+ $("script").each(function () {
+ if(this.src.toString().match(/jquery\.jstree[^\/]*?\.js(\?.*)?$/)) {
+ $.jstree._themes = this.src.toString().replace(/jquery\.jstree[^\/]*?\.js(\?.*)?$/, "") + 'themes/';
+ return false;
+ }
+ });
+ }
+ if($.jstree._themes === false) { $.jstree._themes = "themes/"; }
+ });
+ // include the themes plugin by default
+ $.jstree.defaults.plugins.push("themes");
+})(jQuery);
+//*/
+
+/*
+ * jsTree hotkeys plugin 1.0
+ * Enables keyboard navigation for all tree instances
+ * Depends on the jstree ui & jquery hotkeys plugins
+ */
+(function ($) {
+ var bound = [];
+ function exec(i, event) {
+ var f = $.jstree._focused(), tmp;
+ if(f && f.data && f.data.hotkeys && f.data.hotkeys.enabled) {
+ tmp = f._get_settings().hotkeys[i];
+ if(tmp) { return tmp.call(f, event); }
+ }
+ }
+ $.jstree.plugin("hotkeys", {
+ __init : function () {
+ if(typeof $.hotkeys === "undefined") { throw "jsTree hotkeys: jQuery hotkeys plugin not included."; }
+ if(!this.data.ui) { throw "jsTree hotkeys: jsTree UI plugin not included."; }
+ $.each(this._get_settings().hotkeys, function (i, val) {
+ if($.inArray(i, bound) == -1) {
+ $(document).bind("keydown", i, function (event) { return exec(i, event); });
+ bound.push(i);
+ }
+ });
+ this.enable_hotkeys();
+ },
+ defaults : {
+ "up" : function () {
+ var o = this.data.ui.hovered || this.data.ui.last_selected || -1;
+ this.hover_node(this._get_prev(o));
+ return false;
+ },
+ "down" : function () {
+ var o = this.data.ui.hovered || this.data.ui.last_selected || -1;
+ this.hover_node(this._get_next(o));
+ return false;
+ },
+ "left" : function () {
+ var o = this.data.ui.hovered || this.data.ui.last_selected;
+ if(o) {
+ if(o.hasClass("jstree-open")) { this.close_node(o); }
+ else { this.hover_node(this._get_prev(o)); }
+ }
+ return false;
+ },
+ "right" : function () {
+ var o = this.data.ui.hovered || this.data.ui.last_selected;
+ if(o && o.length) {
+ if(o.hasClass("jstree-closed")) { this.open_node(o); }
+ else { this.hover_node(this._get_next(o)); }
+ }
+ return false;
+ },
+ "space" : function () {
+ if(this.data.ui.hovered) { this.data.ui.hovered.children("a:eq(0)").click(); }
+ return false;
+ },
+ "ctrl+space" : function (event) {
+ event.type = "click";
+ if(this.data.ui.hovered) { this.data.ui.hovered.children("a:eq(0)").trigger(event); }
+ return false;
+ },
+ "f2" : function () { this.rename(this.data.ui.hovered || this.data.ui.last_selected); },
+ "del" : function () { this.remove(this.data.ui.hovered || this._get_node(null)); }
+ },
+ _fn : {
+ enable_hotkeys : function () {
+ this.data.hotkeys.enabled = true;
+ },
+ disable_hotkeys : function () {
+ this.data.hotkeys.enabled = false;
+ }
+ }
+ });
+})(jQuery);
+//*/
+
+/*
+ * jsTree JSON 1.0
+ * The JSON data store. Datastores are build by overriding the `load_node` and `_is_loaded` functions.
+ */
+(function ($) {
+ $.jstree.plugin("json_data", {
+ defaults : {
+ data : false,
+ ajax : false,
+ correct_state : true,
+ progressive_render : false
+ },
+ _fn : {
+ load_node : function (obj, s_call, e_call) { var _this = this; this.load_node_json(obj, function () { _this.__callback({ "obj" : obj }); s_call.call(this); }, e_call); },
+ _is_loaded : function (obj) {
+ var s = this._get_settings().json_data, d;
+ obj = this._get_node(obj);
+ if(obj && obj !== -1 && s.progressive_render && !obj.is(".jstree-open, .jstree-leaf") && obj.children("ul").children("li").length === 0 && obj.data("jstree-children")) {
+ d = this._parse_json(obj.data("jstree-children"));
+ if(d) {
+ obj.append(d);
+ $.removeData(obj, "jstree-children");
+ }
+ this.clean_node(obj);
+ return true;
+ }
+ return obj == -1 || !obj || !s.ajax || obj.is(".jstree-open, .jstree-leaf") || obj.children("ul").children("li").size() > 0;
+ },
+ load_node_json : function (obj, s_call, e_call) {
+ var s = this.get_settings().json_data, d,
+ error_func = function () {},
+ success_func = function () {};
+ obj = this._get_node(obj);
+ if(obj && obj !== -1) {
+ if(obj.data("jstree-is-loading")) { return; }
+ else { obj.data("jstree-is-loading",true); }
+ }
+ switch(!0) {
+ case (!s.data && !s.ajax): throw "Neither data nor ajax settings supplied.";
+ case (!!s.data && !s.ajax) || (!!s.data && !!s.ajax && (!obj || obj === -1)):
+ if(!obj || obj == -1) {
+ d = this._parse_json(s.data);
+ if(d) {
+ this.get_container().children("ul").empty().append(d.children());
+ this.clean_node();
+ }
+ else {
+ if(s.correct_state) { this.get_container().children("ul").empty(); }
+ }
+ }
+ if(s_call) { s_call.call(this); }
+ break;
+ case (!s.data && !!s.ajax) || (!!s.data && !!s.ajax && obj && obj !== -1):
+ error_func = function (x, t, e) {
+ var ef = this.get_settings().json_data.ajax.error;
+ if(ef) { ef.call(this, x, t, e); }
+ if(obj != -1 && obj.length) {
+ obj.children(".jstree-loading").removeClass("jstree-loading");
+ obj.data("jstree-is-loading",false);
+ if(t === "success" && s.correct_state) { obj.removeClass("jstree-open jstree-closed").addClass("jstree-leaf"); }
+ }
+ else {
+ if(t === "success" && s.correct_state) { this.get_container().children("ul").empty(); }
+ }
+ if(e_call) { e_call.call(this); }
+ };
+ success_func = function (d, t, x) {
+ var sf = this.get_settings().json_data.ajax.success;
+ if(sf) { d = sf.call(this,d,t,x) || d; }
+ if(d === "" || (!$.isArray(d) && !$.isPlainObject(d))) {
+ return error_func.call(this, x, t, "");
+ }
+ d = this._parse_json(d);
+ if(d) {
+ if(obj === -1 || !obj) { this.get_container().children("ul").empty().append(d.children()); }
+ else { obj.append(d).children(".jstree-loading").removeClass("jstree-loading"); obj.data("jstree-is-loading",false); }
+ this.clean_node(obj);
+ if(s_call) { s_call.call(this); }
+ }
+ else {
+ if(obj === -1 || !obj) {
+ if(s.correct_state) {
+ this.get_container().children("ul").empty();
+ if(s_call) { s_call.call(this); }
+ }
+ }
+ else {
+ obj.children(".jstree-loading").removeClass("jstree-loading");
+ obj.data("jstree-is-loading",false);
+ if(s.correct_state) {
+ obj.removeClass("jstree-open jstree-closed").addClass("jstree-leaf");
+ if(s_call) { s_call.call(this); }
+ }
+ }
+ }
+ };
+ s.ajax.context = this;
+ s.ajax.error = error_func;
+ s.ajax.success = success_func;
+ if(!s.ajax.dataType) { s.ajax.dataType = "json"; }
+ if($.isFunction(s.ajax.url)) { s.ajax.url = s.ajax.url.call(this, obj); }
+ if($.isFunction(s.ajax.data)) { s.ajax.data = s.ajax.data.call(this, obj); }
+ $.ajax(s.ajax);
+ break;
+ }
+ },
+ _parse_json : function (js, is_callback) {
+ var d = false,
+ p = this._get_settings(),
+ s = p.json_data,
+ t = p.core.html_titles,
+ tmp, i, j, ul1, ul2;
+
+ if(!js) { return d; }
+ if($.isFunction(js)) {
+ js = js.call(this);
+ }
+ if($.isArray(js)) {
+ d = $();
+ if(!js.length) { return false; }
+ for(i = 0, j = js.length; i < j; i++) {
+ tmp = this._parse_json(js[i], true);
+ if(tmp.length) { d = d.add(tmp); }
+ }
+ }
+ else {
+ if(typeof js == "string") { js = { data : js }; }
+ if(!js.data && js.data !== "") { return d; }
+ d = $("<li>");
+ if(js.attr) { d.attr(js.attr); }
+ if(js.metadata) { d.data("jstree", js.metadata); }
+ if(js.state) { d.addClass("jstree-" + js.state); }
+ if(!$.isArray(js.data)) { tmp = js.data; js.data = []; js.data.push(tmp); }
+ $.each(js.data, function (i, m) {
+ tmp = $("<a>");
+ if($.isFunction(m)) { m = m.call(this, js); }
+ if(typeof m == "string") { tmp.attr('href','#')[ t ? "html" : "text" ](m); }
+ else {
+ if(!m.attr) { m.attr = {}; }
+ if(!m.attr.href) { m.attr.href = '#'; }
+ tmp.attr(m.attr)[ t ? "html" : "text" ](m.title);
+ if(m.language) { tmp.addClass(m.language); }
+ }
+ tmp.prepend("<ins class='jstree-icon'>&#160;</ins>");
+ if(!m.icon && js.icon) { m.icon = js.icon; }
+ if(m.icon) {
+ if(m.icon.indexOf("/") === -1) { tmp.children("ins").addClass(m.icon); }
+ else { tmp.children("ins").css("background","url('" + m.icon + "') center center no-repeat"); }
+ }
+ d.append(tmp);
+ });
+ d.prepend("<ins class='jstree-icon'>&#160;</ins>");
+ if(js.children) {
+ if(s.progressive_render && js.state !== "open") {
+ d.addClass("jstree-closed").data("jstree-children", js.children);
+ }
+ else {
+ if($.isFunction(js.children)) {
+ js.children = js.children.call(this, js);
+ }
+ if($.isArray(js.children) && js.children.length) {
+ tmp = this._parse_json(js.children, true);
+ if(tmp.length) {
+ ul2 = $("<ul>");
+ ul2.append(tmp);
+ d.append(ul2);
+ }
+ }
+ }
+ }
+ }
+ if(!is_callback) {
+ ul1 = $("<ul>");
+ ul1.append(d);
+ d = ul1;
+ }
+ return d;
+ },
+ get_json : function (obj, li_attr, a_attr, is_callback) {
+ var result = [],
+ s = this._get_settings(),
+ _this = this,
+ tmp1, tmp2, li, a, t, lang;
+ obj = this._get_node(obj);
+ if(!obj || obj === -1) { obj = this.get_container().find("> ul > li"); }
+ li_attr = $.isArray(li_attr) ? li_attr : [ "id", "class" ];
+ if(!is_callback && this.data.types) { li_attr.push(s.types.type_attr); }
+ a_attr = $.isArray(a_attr) ? a_attr : [ ];
+
+ obj.each(function () {
+ li = $(this);
+ tmp1 = { data : [] };
+ if(li_attr.length) { tmp1.attr = { }; }
+ $.each(li_attr, function (i, v) {
+ tmp2 = li.attr(v);
+ if(tmp2 && tmp2.length && tmp2.replace(/jstree[^ ]*|$/ig,'').length) {
+ tmp1.attr[v] = tmp2.replace(/jstree[^ ]*|$/ig,'');
+ }
+ });
+ if(li.hasClass("jstree-open")) { tmp1.state = "open"; }
+ if(li.hasClass("jstree-closed")) { tmp1.state = "closed"; }
+ a = li.children("a");
+ a.each(function () {
+ t = $(this);
+ if(
+ a_attr.length ||
+ $.inArray("languages", s.plugins) !== -1 ||
+ t.children("ins").get(0).style.backgroundImage.length ||
+ (t.children("ins").get(0).className && t.children("ins").get(0).className.replace(/jstree[^ ]*|$/ig,'').length)
+ ) {
+ lang = false;
+ if($.inArray("languages", s.plugins) !== -1 && $.isArray(s.languages) && s.languages.length) {
+ $.each(s.languages, function (l, lv) {
+ if(t.hasClass(lv)) {
+ lang = lv;
+ return false;
+ }
+ });
+ }
+ tmp2 = { attr : { }, title : _this.get_text(t, lang) };
+ $.each(a_attr, function (k, z) {
+ tmp1.attr[z] = (t.attr(z) || "").replace(/jstree[^ ]*|$/ig,'');
+ });
+ $.each(s.languages, function (k, z) {
+ if(t.hasClass(z)) { tmp2.language = z; return true; }
+ });
+ if(t.children("ins").get(0).className.replace(/jstree[^ ]*|$/ig,'').replace(/^\s+$/ig,"").length) {
+ tmp2.icon = t.children("ins").get(0).className.replace(/jstree[^ ]*|$/ig,'').replace(/^\s+$/ig,"");
+ }
+ if(t.children("ins").get(0).style.backgroundImage.length) {
+ tmp2.icon = t.children("ins").get(0).style.backgroundImage.replace("url(","").replace(")","");
+ }
+ }
+ else {
+ tmp2 = _this.get_text(t);
+ }
+ if(a.length > 1) { tmp1.data.push(tmp2); }
+ else { tmp1.data = tmp2; }
+ });
+ li = li.find("> ul > li");
+ if(li.length) { tmp1.children = _this.get_json(li, li_attr, a_attr, true); }
+ result.push(tmp1);
+ });
+ return result;
+ }
+ }
+ });
+})(jQuery);
+//*/
+
+/*
+ * jsTree languages plugin 1.0
+ * Adds support for multiple language versions in one tree
+ * This basically allows for many titles coexisting in one node, but only one of them being visible at any given time
+ * This is useful for maintaining the same structure in many languages (hence the name of the plugin)
+ */
+(function ($) {
+ $.jstree.plugin("languages", {
+ __init : function () { this._load_css(); },
+ defaults : [],
+ _fn : {
+ set_lang : function (i) {
+ var langs = this._get_settings().languages,
+ st = false,
+ selector = ".jstree-" + this.get_index() + ' a';
+ if(!$.isArray(langs) || langs.length === 0) { return false; }
+ if($.inArray(i,langs) == -1) {
+ if(!!langs[i]) { i = langs[i]; }
+ else { return false; }
+ }
+ if(i == this.data.languages.current_language) { return true; }
+ st = $.vakata.css.get_css(selector + "." + this.data.languages.current_language, false, this.data.languages.language_css);
+ if(st !== false) { st.style.display = "none"; }
+ st = $.vakata.css.get_css(selector + "." + i, false, this.data.languages.language_css);
+ if(st !== false) { st.style.display = ""; }
+ this.data.languages.current_language = i;
+ this.__callback(i);
+ return true;
+ },
+ get_lang : function () {
+ return this.data.languages.current_language;
+ },
+ get_text : function (obj, lang) {
+ obj = this._get_node(obj) || this.data.ui.last_selected;
+ if(!obj.size()) { return false; }
+ var langs = this._get_settings().languages,
+ s = this._get_settings().core.html_titles;
+ if($.isArray(langs) && langs.length) {
+ lang = (lang && $.inArray(lang,langs) != -1) ? lang : this.data.languages.current_language;
+ obj = obj.children("a." + lang);
+ }
+ else { obj = obj.children("a:eq(0)"); }
+ if(s) {
+ obj = obj.clone();
+ obj.children("INS").remove();
+ return obj.html();
+ }
+ else {
+ obj = obj.contents().filter(function() { return this.nodeType == 3; })[0];
+ return obj.nodeValue;
+ }
+ },
+ set_text : function (obj, val, lang) {
+ obj = this._get_node(obj) || this.data.ui.last_selected;
+ if(!obj.size()) { return false; }
+ var langs = this._get_settings().languages,
+ s = this._get_settings().core.html_titles,
+ tmp;
+ if($.isArray(langs) && langs.length) {
+ lang = (lang && $.inArray(lang,langs) != -1) ? lang : this.data.languages.current_language;
+ obj = obj.children("a." + lang);
+ }
+ else { obj = obj.children("a:eq(0)"); }
+ if(s) {
+ tmp = obj.children("INS").clone();
+ obj.html(val).prepend(tmp);
+ this.__callback({ "obj" : obj, "name" : val, "lang" : lang });
+ return true;
+ }
+ else {
+ obj = obj.contents().filter(function() { return this.nodeType == 3; })[0];
+ this.__callback({ "obj" : obj, "name" : val, "lang" : lang });
+ return (obj.nodeValue = val);
+ }
+ },
+ _load_css : function () {
+ var langs = this._get_settings().languages,
+ str = "/* languages css */",
+ selector = ".jstree-" + this.get_index() + ' a',
+ ln;
+ if($.isArray(langs) && langs.length) {
+ this.data.languages.current_language = langs[0];
+ for(ln = 0; ln < langs.length; ln++) {
+ str += selector + "." + langs[ln] + " {";
+ if(langs[ln] != this.data.languages.current_language) { str += " display:none; "; }
+ str += " } ";
+ }
+ this.data.languages.language_css = $.vakata.css.add_sheet({ 'str' : str });
+ }
+ },
+ create_node : function (obj, position, js, callback) {
+ var t = this.__call_old(true, obj, position, js, function (t) {
+ var langs = this._get_settings().languages,
+ a = t.children("a"),
+ ln;
+ if($.isArray(langs) && langs.length) {
+ for(ln = 0; ln < langs.length; ln++) {
+ if(!a.is("." + langs[ln])) {
+ t.append(a.eq(0).clone().removeClass(langs.join(" ")).addClass(langs[ln]));
+ }
+ }
+ a.not("." + langs.join(", .")).remove();
+ }
+ if(callback) { callback.call(this, t); }
+ });
+ return t;
+ }
+ }
+ });
+})(jQuery);
+//*/
+
+/*
+ * jsTree cookies plugin 1.0
+ * Stores the currently opened/selected nodes in a cookie and then restores them
+ * Depends on the jquery.cookie plugin
+ */
+(function ($) {
+ $.jstree.plugin("cookies", {
+ __init : function () {
+ if(typeof $.cookie === "undefined") { throw "jsTree cookie: jQuery cookie plugin not included."; }
+
+ var s = this._get_settings().cookies,
+ tmp;
+ if(!!s.save_opened) {
+ tmp = $.cookie(s.save_opened);
+ if(tmp && tmp.length) { this.data.core.to_open = tmp.split(","); }
+ }
+ if(!!s.save_selected) {
+ tmp = $.cookie(s.save_selected);
+ if(tmp && tmp.length && this.data.ui) { this.data.ui.to_select = tmp.split(","); }
+ }
+ this.get_container()
+ .one( ( this.data.ui ? "reselect" : "reopen" ) + ".jstree", $.proxy(function () {
+ this.get_container()
+ .bind("open_node.jstree close_node.jstree select_node.jstree deselect_node.jstree", $.proxy(function (e) {
+ if(this._get_settings().cookies.auto_save) { this.save_cookie((e.handleObj.namespace + e.handleObj.type).replace("jstree","")); }
+ }, this));
+ }, this));
+ },
+ defaults : {
+ save_opened : "jstree_open",
+ save_selected : "jstree_select",
+ auto_save : true,
+ cookie_options : {}
+ },
+ _fn : {
+ save_cookie : function (c) {
+ if(this.data.core.refreshing) { return; }
+ var s = this._get_settings().cookies;
+ if(!c) { // if called manually and not by event
+ if(s.save_opened) {
+ this.save_opened();
+ $.cookie(s.save_opened, this.data.core.to_open.join(","), s.cookie_options);
+ }
+ if(s.save_selected && this.data.ui) {
+ this.save_selected();
+ $.cookie(s.save_selected, this.data.ui.to_select.join(","), s.cookie_options);
+ }
+ return;
+ }
+ switch(c) {
+ case "open_node":
+ case "close_node":
+ if(!!s.save_opened) {
+ this.save_opened();
+ $.cookie(s.save_opened, this.data.core.to_open.join(","), s.cookie_options);
+ }
+ break;
+ case "select_node":
+ case "deselect_node":
+ if(!!s.save_selected && this.data.ui) {
+ this.save_selected();
+ $.cookie(s.save_selected, this.data.ui.to_select.join(","), s.cookie_options);
+ }
+ break;
+ }
+ }
+ }
+ });
+ // include cookies by default
+ $.jstree.defaults.plugins.push("cookies");
+})(jQuery);
+//*/
+
+/*
+ * jsTree sort plugin 1.0
+ * Sorts items alphabetically (or using any other function)
+ */
+(function ($) {
+ $.jstree.plugin("sort", {
+ __init : function () {
+ this.get_container()
+ .bind("load_node.jstree", $.proxy(function (e, data) {
+ var obj = this._get_node(data.rslt.obj);
+ obj = obj === -1 ? this.get_container().children("ul") : obj.children("ul");
+ this.sort(obj);
+ }, this))
+ .bind("rename_node.jstree", $.proxy(function (e, data) {
+ this.sort(data.rslt.obj.parent());
+ }, this))
+ .bind("move_node.jstree", $.proxy(function (e, data) {
+ var m = data.rslt.np == -1 ? this.get_container() : data.rslt.np;
+ this.sort(m.children("ul"));
+ }, this));
+ },
+ defaults : function (a, b) { return this.get_text(a) > this.get_text(b) ? 1 : -1; },
+ _fn : {
+ sort : function (obj) {
+ var s = this._get_settings().sort,
+ t = this;
+ obj.append($.makeArray(obj.children("li")).sort($.proxy(s, t)));
+ obj.find("> li > ul").each(function() { t.sort($(this)); });
+ this.clean_node(obj);
+ }
+ }
+ });
+})(jQuery);
+//*/
+
+/*
+ * jsTree DND plugin 1.0
+ * Drag and drop plugin for moving/copying nodes
+ */
+(function ($) {
+ var o = false,
+ r = false,
+ m = false,
+ sli = false,
+ sti = false,
+ dir1 = false,
+ dir2 = false;
+ $.vakata.dnd = {
+ is_down : false,
+ is_drag : false,
+ helper : false,
+ scroll_spd : 10,
+ init_x : 0,
+ init_y : 0,
+ threshold : 5,
+ user_data : {},
+
+ drag_start : function (e, data, html) {
+ if($.vakata.dnd.is_drag) { $.vakata.drag_stop({}); }
+ try {
+ e.currentTarget.unselectable = "on";
+ e.currentTarget.onselectstart = function() { return false; };
+ if(e.currentTarget.style) { e.currentTarget.style.MozUserSelect = "none"; }
+ } catch(err) { }
+ $.vakata.dnd.init_x = e.pageX;
+ $.vakata.dnd.init_y = e.pageY;
+ $.vakata.dnd.user_data = data;
+ $.vakata.dnd.is_down = true;
+ $.vakata.dnd.helper = $("<div id='vakata-dragged'>").html(html).css("opacity", "0.75");
+ $(document).bind("mousemove", $.vakata.dnd.drag);
+ $(document).bind("mouseup", $.vakata.dnd.drag_stop);
+ return false;
+ },
+ drag : function (e) {
+ if(!$.vakata.dnd.is_down) { return; }
+ if(!$.vakata.dnd.is_drag) {
+ if(Math.abs(e.pageX - $.vakata.dnd.init_x) > 5 || Math.abs(e.pageY - $.vakata.dnd.init_y) > 5) {
+ $.vakata.dnd.helper.appendTo("body");
+ $.vakata.dnd.is_drag = true;
+ $(document).triggerHandler("drag_start.vakata", { "event" : e, "data" : $.vakata.dnd.user_data });
+ }
+ else { return; }
+ }
+
+ // maybe use a scrolling parent element instead of document?
+ if(e.type === "mousemove") { // thought of adding scroll in order to move the helper, but mouse poisition is n/a
+ var d = $(document), t = d.scrollTop(), l = d.scrollLeft();
+ if(e.pageY - t < 20) {
+ if(sti && dir1 === "down") { clearInterval(sti); sti = false; }
+ if(!sti) { dir1 = "up"; sti = setInterval(function () { $(document).scrollTop($(document).scrollTop() - $.vakata.dnd.scroll_spd); }, 150); }
+ }
+ else {
+ if(sti && dir1 === "up") { clearInterval(sti); sti = false; }
+ }
+ if($(window).height() - (e.pageY - t) < 20) {
+ if(sti && dir1 === "up") { clearInterval(sti); sti = false; }
+ if(!sti) { dir1 = "down"; sti = setInterval(function () { $(document).scrollTop($(document).scrollTop() + $.vakata.dnd.scroll_spd); }, 150); }
+ }
+ else {
+ if(sti && dir1 === "down") { clearInterval(sti); sti = false; }
+ }
+
+ if(e.pageX - l < 20) {
+ if(sli && dir2 === "right") { clearInterval(sli); sli = false; }
+ if(!sli) { dir2 = "left"; sli = setInterval(function () { $(document).scrollLeft($(document).scrollLeft() - $.vakata.dnd.scroll_spd); }, 150); }
+ }
+ else {
+ if(sli && dir2 === "left") { clearInterval(sli); sli = false; }
+ }
+ if($(window).width() - (e.pageX - l) < 20) {
+ if(sli && dir2 === "left") { clearInterval(sli); sli = false; }
+ if(!sli) { dir2 = "right"; sli = setInterval(function () { $(document).scrollLeft($(document).scrollLeft() + $.vakata.dnd.scroll_spd); }, 150); }
+ }
+ else {
+ if(sli && dir2 === "right") { clearInterval(sli); sli = false; }
+ }
+ }
+
+ $.vakata.dnd.helper.css({ left : (e.pageX + 5) + "px", top : (e.pageY + 10) + "px" });
+ $(document).triggerHandler("drag.vakata", { "event" : e, "data" : $.vakata.dnd.user_data });
+ },
+ drag_stop : function (e) {
+ $(document).unbind("mousemove", $.vakata.dnd.drag);
+ $(document).unbind("mouseup", $.vakata.dnd.drag_stop);
+ $(document).triggerHandler("drag_stop.vakata", { "event" : e, "data" : $.vakata.dnd.user_data });
+ $.vakata.dnd.helper.remove();
+ $.vakata.dnd.init_x = 0;
+ $.vakata.dnd.init_y = 0;
+ $.vakata.dnd.user_data = {};
+ $.vakata.dnd.is_down = false;
+ $.vakata.dnd.is_drag = false;
+ }
+ };
+ $(function() {
+ var css_string = '#vakata-dragged { display:block; margin:0 0 0 0; padding:4px 4px 4px 24px; position:absolute; top:-2000px; line-height:16px; z-index:10000; } ';
+ $.vakata.css.add_sheet({ str : css_string });
+ });
+
+ $.jstree.plugin("dnd", {
+ __init : function () {
+ this.data.dnd = {
+ active : false,
+ after : false,
+ inside : false,
+ before : false,
+ off : false,
+ prepared : false,
+ w : 0,
+ to1 : false,
+ to2 : false,
+ cof : false,
+ cw : false,
+ ch : false,
+ i1 : false,
+ i2 : false
+ };
+ this.get_container()
+ .bind("mouseenter.jstree", $.proxy(function () {
+ if($.vakata.dnd.is_drag && $.vakata.dnd.user_data.jstree && this.data.themes) {
+ m.attr("class", "jstree-" + this.data.themes.theme);
+ $.vakata.dnd.helper.attr("class", "jstree-dnd-helper jstree-" + this.data.themes.theme);
+ }
+ }, this))
+ .bind("mouseleave.jstree", $.proxy(function () {
+ if($.vakata.dnd.is_drag && $.vakata.dnd.user_data.jstree) {
+ if(this.data.dnd.i1) { clearInterval(this.data.dnd.i1); }
+ if(this.data.dnd.i2) { clearInterval(this.data.dnd.i2); }
+ }
+ }, this))
+ .bind("mousemove.jstree", $.proxy(function (e) {
+ if($.vakata.dnd.is_drag && $.vakata.dnd.user_data.jstree) {
+ var cnt = this.get_container()[0];
+
+ // Horizontal scroll
+ if(e.pageX + 24 > this.data.dnd.cof.left + this.data.dnd.cw) {
+ if(this.data.dnd.i1) { clearInterval(this.data.dnd.i1); }
+ this.data.dnd.i1 = setInterval($.proxy(function () { this.scrollLeft += $.vakata.dnd.scroll_spd; }, cnt), 100);
+ }
+ else if(e.pageX - 24 < this.data.dnd.cof.left) {
+ if(this.data.dnd.i1) { clearInterval(this.data.dnd.i1); }
+ this.data.dnd.i1 = setInterval($.proxy(function () { this.scrollLeft -= $.vakata.dnd.scroll_spd; }, cnt), 100);
+ }
+ else {
+ if(this.data.dnd.i1) { clearInterval(this.data.dnd.i1); }
+ }
+
+ // Vertical scroll
+ if(e.pageY + 24 > this.data.dnd.cof.top + this.data.dnd.ch) {
+ if(this.data.dnd.i2) { clearInterval(this.data.dnd.i2); }
+ this.data.dnd.i2 = setInterval($.proxy(function () { this.scrollTop += $.vakata.dnd.scroll_spd; }, cnt), 100);
+ }
+ else if(e.pageY - 24 < this.data.dnd.cof.top) {
+ if(this.data.dnd.i2) { clearInterval(this.data.dnd.i2); }
+ this.data.dnd.i2 = setInterval($.proxy(function () { this.scrollTop -= $.vakata.dnd.scroll_spd; }, cnt), 100);
+ }
+ else {
+ if(this.data.dnd.i2) { clearInterval(this.data.dnd.i2); }
+ }
+
+ }
+ }, this))
+ .delegate("a", "mousedown.jstree", $.proxy(function (e) {
+ if(e.which === 1) {
+ this.start_drag(e.currentTarget, e);
+ return false;
+ }
+ }, this))
+ .delegate("a", "mouseenter.jstree", $.proxy(function (e) {
+ if($.vakata.dnd.is_drag && $.vakata.dnd.user_data.jstree) {
+ this.dnd_enter(e.currentTarget);
+ }
+ }, this))
+ .delegate("a", "mousemove.jstree", $.proxy(function (e) {
+ if($.vakata.dnd.is_drag && $.vakata.dnd.user_data.jstree) {
+ if(typeof this.data.dnd.off.top === "undefined") { this.data.dnd.off = $(e.target).offset(); }
+ this.data.dnd.w = (e.pageY - (this.data.dnd.off.top || 0)) % this.data.core.li_height;
+ if(this.data.dnd.w < 0) { this.data.dnd.w += this.data.core.li_height; }
+ this.dnd_show();
+ }
+ }, this))
+ .delegate("a", "mouseleave.jstree", $.proxy(function (e) {
+ if($.vakata.dnd.is_drag && $.vakata.dnd.user_data.jstree) {
+ this.data.dnd.after = false;
+ this.data.dnd.before = false;
+ this.data.dnd.inside = false;
+ $.vakata.dnd.helper.children("ins").attr("class","jstree-invalid");
+ m.hide();
+ if(r && r[0] === e.target.parentNode) {
+ if(this.data.dnd.to1) {
+ clearTimeout(this.data.dnd.to1);
+ this.data.dnd.to1 = false;
+ }
+ if(this.data.dnd.to2) {
+ clearTimeout(this.data.dnd.to2);
+ this.data.dnd.to2 = false;
+ }
+ }
+ }
+ }, this))
+ .delegate("a", "mouseup.jstree", $.proxy(function (e) {
+ if($.vakata.dnd.is_drag && $.vakata.dnd.user_data.jstree) {
+ this.dnd_finish(e);
+ }
+ }, this));
+
+ $(document)
+ .bind("drag_stop.vakata", $.proxy(function () {
+ this.data.dnd.after = false;
+ this.data.dnd.before = false;
+ this.data.dnd.inside = false;
+ this.data.dnd.off = false;
+ this.data.dnd.prepared = false;
+ this.data.dnd.w = false;
+ this.data.dnd.to1 = false;
+ this.data.dnd.to2 = false;
+ this.data.dnd.active = false;
+ this.data.dnd.foreign = false;
+ if(m) { m.css({ "top" : "-2000px" }); }
+ }, this))
+ .bind("drag_start.vakata", $.proxy(function (e, data) {
+ if(data.data.jstree) {
+ var et = $(data.event.target);
+ if(et.closest(".jstree").hasClass("jstree-" + this.get_index())) {
+ this.dnd_enter(et);
+ }
+ }
+ }, this));
+
+ var s = this._get_settings().dnd;
+ if(s.drag_target) {
+ $(document)
+ .delegate(s.drag_target, "mousedown.jstree", $.proxy(function (e) {
+ o = e.target;
+ $.vakata.dnd.drag_start(e, { jstree : true, obj : e.target }, "<ins class='jstree-icon'></ins>" + $(e.target).text() );
+ if(this.data.themes) {
+ m.attr("class", "jstree-" + this.data.themes.theme);
+ $.vakata.dnd.helper.attr("class", "jstree-dnd-helper jstree-" + this.data.themes.theme);
+ }
+ $.vakata.dnd.helper.children("ins").attr("class","jstree-invalid");
+ var cnt = this.get_container();
+ this.data.dnd.cof = cnt.offset();
+ this.data.dnd.cw = parseInt(cnt.width(),10);
+ this.data.dnd.ch = parseInt(cnt.height(),10);
+ this.data.dnd.foreign = true;
+ return false;
+ }, this));
+ }
+ if(s.drop_target) {
+ $(document)
+ .delegate(s.drop_target, "mouseenter.jstree", $.proxy(function (e) {
+ if(this.data.dnd.active && this._get_settings().dnd.drop_check.call(this, { "o" : o, "r" : $(e.target) })) {
+ $.vakata.dnd.helper.children("ins").attr("class","jstree-ok");
+ }
+ }, this))
+ .delegate(s.drop_target, "mouseleave.jstree", $.proxy(function (e) {
+ if(this.data.dnd.active) {
+ $.vakata.dnd.helper.children("ins").attr("class","jstree-invalid");
+ }
+ }, this))
+ .delegate(s.drop_target, "mouseup.jstree", $.proxy(function (e) {
+ if(this.data.dnd.active && $.vakata.dnd.helper.children("ins").hasClass("jstree-ok")) {
+ this._get_settings().dnd.drop_finish.call(this, { "o" : o, "r" : $(e.target) });
+ }
+ }, this));
+ }
+ },
+ defaults : {
+ copy_modifier : "ctrl",
+ check_timeout : 200,
+ open_timeout : 500,
+ drop_target : ".jstree-drop",
+ drop_check : function (data) { return true; },
+ drop_finish : $.noop,
+ drag_target : ".jstree-draggable",
+ drag_finish : $.noop,
+ drag_check : function (data) { return { after : false, before : false, inside : true }; }
+ },
+ _fn : {
+ dnd_prepare : function () {
+ if(!r || !r.length) { return; }
+ this.data.dnd.off = r.offset();
+ if(this._get_settings().core.rtl) {
+ this.data.dnd.off.right = this.data.dnd.off.left + r.width();
+ }
+ if(this.data.dnd.foreign) {
+ var a = this._get_settings().dnd.drag_check.call(this, { "o" : o, "r" : r });
+ this.data.dnd.after = a.after;
+ this.data.dnd.before = a.before;
+ this.data.dnd.inside = a.inside;
+ this.data.dnd.prepared = true;
+ return this.dnd_show();
+ }
+ this.prepare_move(o, r, "before");
+ this.data.dnd.before = this.check_move();
+ this.prepare_move(o, r, "after");
+ this.data.dnd.after = this.check_move();
+ if(this._is_loaded(r)) {
+ this.prepare_move(o, r, "inside");
+ this.data.dnd.inside = this.check_move();
+ }
+ else {
+ this.data.dnd.inside = false;
+ }
+ this.data.dnd.prepared = true;
+ return this.dnd_show();
+ },
+ dnd_show : function () {
+ if(!this.data.dnd.prepared) { return; }
+ var o = ["before","inside","after"],
+ r = false,
+ rtl = this._get_settings().core.rtl,
+ pos;
+ if(this.data.dnd.w < this.data.core.li_height/3) { o = ["before","inside","after"]; }
+ else if(this.data.dnd.w <= this.data.core.li_height*2/3) {
+ o = this.data.dnd.w < this.data.core.li_height/2 ? ["inside","before","after"] : ["inside","after","before"];
+ }
+ else { o = ["after","inside","before"]; }
+ $.each(o, $.proxy(function (i, val) {
+ if(this.data.dnd[val]) {
+ $.vakata.dnd.helper.children("ins").attr("class","jstree-ok");
+ r = val;
+ return false;
+ }
+ }, this));
+ if(r === false) { $.vakata.dnd.helper.children("ins").attr("class","jstree-invalid"); }
+
+ pos = rtl ? (this.data.dnd.off.right - 18) : (this.data.dnd.off.left + 10);
+ switch(r) {
+ case "before":
+ m.css({ "left" : pos + "px", "top" : (this.data.dnd.off.top - 6) + "px" }).show();
+ break;
+ case "after":
+ m.css({ "left" : pos + "px", "top" : (this.data.dnd.off.top + this.data.core.li_height - 7) + "px" }).show();
+ break;
+ case "inside":
+ m.css({ "left" : pos + ( rtl ? -4 : 4) + "px", "top" : (this.data.dnd.off.top + this.data.core.li_height/2 - 5) + "px" }).show();
+ break;
+ default:
+ m.hide();
+ break;
+ }
+ return r;
+ },
+ dnd_open : function () {
+ this.data.dnd.to2 = false;
+ this.open_node(r, $.proxy(this.dnd_prepare,this), true);
+ },
+ dnd_finish : function (e) {
+ if(this.data.dnd.foreign) {
+ if(this.data.dnd.after || this.data.dnd.before || this.data.dnd.inside) {
+ this._get_settings().dnd.drag_finish.call(this, { "o" : o, "r" : r });
+ }
+ }
+ else {
+ this.dnd_prepare();
+ this.move_node(o, r, this.dnd_show(), e[this._get_settings().dnd.copy_modifier + "Key"]);
+ }
+ o = false;
+ r = false;
+ m.hide();
+ },
+ dnd_enter : function (obj) {
+ var s = this._get_settings().dnd;
+ this.data.dnd.prepared = false;
+ r = this._get_node(obj);
+ if(s.check_timeout) {
+ // do the calculations after a minimal timeout (users tend to drag quickly to the desired location)
+ if(this.data.dnd.to1) { clearTimeout(this.data.dnd.to1); }
+ this.data.dnd.to1 = setTimeout($.proxy(this.dnd_prepare, this), s.check_timeout);
+ }
+ else {
+ this.dnd_prepare();
+ }
+ if(s.open_timeout) {
+ if(this.data.dnd.to2) { clearTimeout(this.data.dnd.to2); }
+ if(r && r.length && r.hasClass("jstree-closed")) {
+ // if the node is closed - open it, then recalculate
+ this.data.dnd.to2 = setTimeout($.proxy(this.dnd_open, this), s.open_timeout);
+ }
+ }
+ else {
+ if(r && r.length && r.hasClass("jstree-closed")) {
+ this.dnd_open();
+ }
+ }
+ },
+ start_drag : function (obj, e) {
+ o = this._get_node(obj);
+ if(this.data.ui && this.is_selected(o)) { o = this._get_node(null, true); }
+ $.vakata.dnd.drag_start(e, { jstree : true, obj : o }, "<ins class='jstree-icon'></ins>" + (o.length > 1 ? "Multiple selection" : this.get_text(o)) );
+ if(this.data.themes) {
+ m.attr("class", "jstree-" + this.data.themes.theme);
+ $.vakata.dnd.helper.attr("class", "jstree-dnd-helper jstree-" + this.data.themes.theme);
+ }
+ var cnt = this.get_container();
+ this.data.dnd.cof = cnt.children("ul").offset();
+ this.data.dnd.cw = parseInt(cnt.width(),10);
+ this.data.dnd.ch = parseInt(cnt.height(),10);
+ this.data.dnd.active = true;
+ }
+ }
+ });
+ $(function() {
+ var css_string = '' +
+ '#vakata-dragged ins { display:block; text-decoration:none; width:16px; height:16px; margin:0 0 0 0; padding:0; position:absolute; top:4px; left:4px; } ' +
+ '#vakata-dragged .jstree-ok { background:green; } ' +
+ '#vakata-dragged .jstree-invalid { background:red; } ' +
+ '#jstree-marker { padding:0; margin:0; line-height:12px; font-size:1px; overflow:hidden; height:12px; width:8px; position:absolute; top:-30px; z-index:10000; background-repeat:no-repeat; display:none; background-color:silver; } ';
+ $.vakata.css.add_sheet({ str : css_string });
+ m = $("<div>").attr({ id : "jstree-marker" }).hide().appendTo("body");
+ $(document).bind("drag_start.vakata", function (e, data) {
+ if(data.data.jstree) {
+ m.show();
+ }
+ });
+ $(document).bind("drag_stop.vakata", function (e, data) {
+ if(data.data.jstree) { m.hide(); }
+ });
+ });
+})(jQuery);
+//*/
+
+/*
+ * jsTree checkbox plugin 1.0
+ * Inserts checkboxes in front of every node
+ * Depends on the ui plugin
+ * DOES NOT WORK NICELY WITH MULTITREE DRAG'N'DROP
+ */
+(function ($) {
+ $.jstree.plugin("checkbox", {
+ __init : function () {
+ this.select_node = this.deselect_node = this.deselect_all = $.noop;
+ this.get_selected = this.get_checked;
+
+ this.get_container()
+ .bind("open_node.jstree create_node.jstree clean_node.jstree", $.proxy(function (e, data) {
+ this._prepare_checkboxes(data.rslt.obj);
+ }, this))
+ .bind("loaded.jstree", $.proxy(function (e) {
+ this._prepare_checkboxes();
+ }, this))
+ .delegate("a", "click.jstree", $.proxy(function (e) {
+ if(this._get_node(e.target).hasClass("jstree-checked")) { this.uncheck_node(e.target); }
+ else { this.check_node(e.target); }
+ if(this.data.ui) { this.save_selected(); }
+ if(this.data.cookies) { this.save_cookie("select_node"); }
+ e.preventDefault();
+ }, this));
+ },
+ __destroy : function () {
+ this.get_container().find(".jstree-checkbox").remove();
+ },
+ _fn : {
+ _prepare_checkboxes : function (obj) {
+ obj = !obj || obj == -1 ? this.get_container() : this._get_node(obj);
+ var c, _this = this, t;
+ obj.each(function () {
+ t = $(this);
+ c = t.is("li") && t.hasClass("jstree-checked") ? "jstree-checked" : "jstree-unchecked";
+ t.find("a").not(":has(.jstree-checkbox)").prepend("<ins class='jstree-checkbox'>&#160;</ins>").parent().not(".jstree-checked, .jstree-unchecked").addClass(c);
+ });
+ if(obj.is("li")) { this._repair_state(obj); }
+ else { obj.find("> ul > li").each(function () { _this._repair_state(this); }); }
+ },
+ change_state : function (obj, state) {
+ obj = this._get_node(obj);
+ state = (state === false || state === true) ? state : obj.hasClass("jstree-checked");
+ if(state) { obj.find("li").andSelf().removeClass("jstree-checked jstree-undetermined").addClass("jstree-unchecked"); }
+ else {
+ obj.find("li").andSelf().removeClass("jstree-unchecked jstree-undetermined").addClass("jstree-checked");
+ if(this.data.ui) { this.data.ui.last_selected = obj; }
+ this.data.checkbox.last_selected = obj;
+ }
+ obj.parentsUntil(".jstree", "li").each(function () {
+ var $this = $(this);
+ if(state) {
+ if($this.children("ul").children(".jstree-checked, .jstree-undetermined").length) {
+ $this.parentsUntil(".jstree", "li").andSelf().removeClass("jstree-checked jstree-unchecked").addClass("jstree-undetermined");
+ return false;
+ }
+ else {
+ $this.removeClass("jstree-checked jstree-undetermined").addClass("jstree-unchecked");
+ }
+ }
+ else {
+ if($this.children("ul").children(".jstree-unchecked, .jstree-undetermined").length) {
+ $this.parentsUntil(".jstree", "li").andSelf().removeClass("jstree-checked jstree-unchecked").addClass("jstree-undetermined");
+ return false;
+ }
+ else {
+ $this.removeClass("jstree-unchecked jstree-undetermined").addClass("jstree-checked");
+ }
+ }
+ });
+ if(this.data.ui) { this.data.ui.selected = this.get_checked(); }
+ this.__callback(obj);
+ },
+ check_node : function (obj) {
+ this.change_state(obj, false);
+ },
+ uncheck_node : function (obj) {
+ this.change_state(obj, true);
+ },
+ check_all : function () {
+ var _this = this;
+ this.get_container().children("ul").children("li").each(function () {
+ _this.check_node(this, false);
+ });
+ },
+ uncheck_all : function () {
+ var _this = this;
+ this.get_container().children("ul").children("li").each(function () {
+ _this.change_state(this, true);
+ });
+ },
+
+ is_checked : function(obj) {
+ obj = this._get_node(obj);
+ return obj.length ? obj.is(".jstree-checked") : false;
+ },
+ get_checked : function (obj) {
+ obj = !obj || obj === -1 ? this.get_container() : this._get_node(obj);
+ return obj.find("> ul > .jstree-checked, .jstree-undetermined > ul > .jstree-checked");
+ },
+ get_unchecked : function (obj) {
+ obj = !obj || obj === -1 ? this.get_container() : this._get_node(obj);
+ return obj.find("> ul > .jstree-unchecked, .jstree-undetermined > ul > .jstree-unchecked");
+ },
+
+ show_checkboxes : function () { this.get_container().children("ul").removeClass("jstree-no-checkboxes"); },
+ hide_checkboxes : function () { this.get_container().children("ul").addClass("jstree-no-checkboxes"); },
+
+ _repair_state : function (obj) {
+ obj = this._get_node(obj);
+ if(!obj.length) { return; }
+ var a = obj.find("> ul > .jstree-checked").length,
+ b = obj.find("> ul > .jstree-undetermined").length,
+ c = obj.find("> ul > li").length;
+
+ if(c === 0) { if(obj.hasClass("jstree-undetermined")) { this.check_node(obj); } }
+ else if(a === 0 && b === 0) { this.uncheck_node(obj); }
+ else if(a === c) { this.check_node(obj); }
+ else {
+ obj.parentsUntil(".jstree","li").removeClass("jstree-checked jstree-unchecked").addClass("jstree-undetermined");
+ }
+ },
+ reselect : function () {
+ if(this.data.ui) {
+ var _this = this,
+ s = this.data.ui.to_select;
+ s = $.map($.makeArray(s), function (n) { return "#" + n.toString().replace(/^#/,"").replace('\\/','/').replace('/','\\/'); });
+ this.deselect_all();
+ $.each(s, function (i, val) { _this.check_node(val); });
+ this.__callback();
+ }
+ }
+ }
+ });
+})(jQuery);
+//*/
+
+/*
+ * jsTree XML 1.0
+ * The XML data store. Datastores are build by overriding the `load_node` and `_is_loaded` functions.
+ */
+(function ($) {
+ $.vakata.xslt = function (xml, xsl, callback) {
+ var rs = "", xm, xs, processor, support;
+ if(document.recalc) {
+ xm = document.createElement('xml');
+ xs = document.createElement('xml');
+ xm.innerHTML = xml;
+ xs.innerHTML = xsl;
+ $("body").append(xm).append(xs);
+ setTimeout( (function (xm, xs, callback) {
+ return function () {
+ callback.call(null, xm.transformNode(xs.XMLDocument));
+ setTimeout( (function (xm, xs) { return function () { jQuery("body").remove(xm).remove(xs); }; })(xm, xs), 200);
+ };
+ }) (xm, xs, callback), 100);
+ return true;
+ }
+ if(typeof window.DOMParser !== "undefined" && typeof window.XMLHttpRequest !== "undefined" && typeof window.XSLTProcessor !== "undefined") {
+ processor = new XSLTProcessor();
+ support = $.isFunction(processor.transformDocument) ? (typeof window.XMLSerializer !== "undefined") : true;
+ if(!support) { return false; }
+ xml = new DOMParser().parseFromString(xml, "text/xml");
+ xsl = new DOMParser().parseFromString(xsl, "text/xml");
+ if($.isFunction(processor.transformDocument)) {
+ rs = document.implementation.createDocument("", "", null);
+ processor.transformDocument(xml, xsl, rs, null);
+ callback.call(null, XMLSerializer().serializeToString(rs));
+ return true;
+ }
+ else {
+ processor.importStylesheet(xsl);
+ rs = processor.transformToFragment(xml, document);
+ callback.call(null, $("<div>").append(rs).html());
+ return true;
+ }
+ }
+ return false;
+ };
+ var xsl = {
+ 'nest' : '<?xml version="1.0" encoding="utf-8" ?>' +
+ '<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" >' +
+ '<xsl:output method="html" encoding="utf-8" omit-xml-declaration="yes" standalone="no" indent="no" media-type="text/html" />' +
+ '<xsl:template match="/">' +
+ ' <xsl:call-template name="nodes">' +
+ ' <xsl:with-param name="node" select="/root" />' +
+ ' </xsl:call-template>' +
+ '</xsl:template>' +
+ '<xsl:template name="nodes">' +
+ ' <xsl:param name="node" />' +
+ ' <ul>' +
+ ' <xsl:for-each select="$node/item">' +
+ ' <xsl:variable name="children" select="count(./item) &gt; 0" />' +
+ ' <li>' +
+ ' <xsl:attribute name="class">' +
+ ' <xsl:if test="position() = last()">jstree-last </xsl:if>' +
+ ' <xsl:choose>' +
+ ' <xsl:when test="@state = \'open\'">jstree-open </xsl:when>' +
+ ' <xsl:when test="$children or @hasChildren or @state = \'closed\'">jstree-closed </xsl:when>' +
+ ' <xsl:otherwise>jstree-leaf </xsl:otherwise>' +
+ ' </xsl:choose>' +
+ ' <xsl:value-of select="@class" />' +
+ ' </xsl:attribute>' +
+ ' <xsl:for-each select="@*">' +
+ ' <xsl:if test="name() != \'class\' and name() != \'state\' and name() != \'hasChildren\'">' +
+ ' <xsl:attribute name="{name()}"><xsl:value-of select="." /></xsl:attribute>' +
+ ' </xsl:if>' +
+ ' </xsl:for-each>' +
+ ' <ins class="jstree-icon"><xsl:text>&#xa0;</xsl:text></ins>' +
+ ' <xsl:for-each select="content/name">' +
+ ' <a>' +
+ ' <xsl:attribute name="href">' +
+ ' <xsl:choose>' +
+ ' <xsl:when test="@href"><xsl:value-of select="@href" /></xsl:when>' +
+ ' <xsl:otherwise>#</xsl:otherwise>' +
+ ' </xsl:choose>' +
+ ' </xsl:attribute>' +
+ ' <xsl:attribute name="class"><xsl:value-of select="@lang" /> <xsl:value-of select="@class" /></xsl:attribute>' +
+ ' <xsl:attribute name="style"><xsl:value-of select="@style" /></xsl:attribute>' +
+ ' <xsl:for-each select="@*">' +
+ ' <xsl:if test="name() != \'style\' and name() != \'class\' and name() != \'href\'">' +
+ ' <xsl:attribute name="{name()}"><xsl:value-of select="." /></xsl:attribute>' +
+ ' </xsl:if>' +
+ ' </xsl:for-each>' +
+ ' <ins>' +
+ ' <xsl:attribute name="class">jstree-icon ' +
+ ' <xsl:if test="string-length(attribute::icon) > 0 and not(contains(@icon,\'/\'))"><xsl:value-of select="@icon" /></xsl:if>' +
+ ' </xsl:attribute>' +
+ ' <xsl:if test="string-length(attribute::icon) > 0 and contains(@icon,\'/\')"><xsl:attribute name="style">background:url(<xsl:value-of select="@icon" />) center center no-repeat;</xsl:attribute></xsl:if>' +
+ ' <xsl:text>&#xa0;</xsl:text>' +
+ ' </ins>' +
+ ' <xsl:value-of select="current()" />' +
+ ' </a>' +
+ ' </xsl:for-each>' +
+ ' <xsl:if test="$children or @hasChildren"><xsl:call-template name="nodes"><xsl:with-param name="node" select="current()" /></xsl:call-template></xsl:if>' +
+ ' </li>' +
+ ' </xsl:for-each>' +
+ ' </ul>' +
+ '</xsl:template>' +
+ '</xsl:stylesheet>',
+
+ 'flat' : '<?xml version="1.0" encoding="utf-8" ?>' +
+ '<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" >' +
+ '<xsl:output method="html" encoding="utf-8" omit-xml-declaration="yes" standalone="no" indent="no" media-type="text/xml" />' +
+ '<xsl:template match="/">' +
+ ' <ul>' +
+ ' <xsl:for-each select="//item[not(@parent_id) or @parent_id=0 or not(@parent_id = //item/@id)]">' + /* the last `or` may be removed */
+ ' <xsl:call-template name="nodes">' +
+ ' <xsl:with-param name="node" select="." />' +
+ ' <xsl:with-param name="is_last" select="number(position() = last())" />' +
+ ' </xsl:call-template>' +
+ ' </xsl:for-each>' +
+ ' </ul>' +
+ '</xsl:template>' +
+ '<xsl:template name="nodes">' +
+ ' <xsl:param name="node" />' +
+ ' <xsl:param name="is_last" />' +
+ ' <xsl:variable name="children" select="count(//item[@parent_id=$node/attribute::id]) &gt; 0" />' +
+ ' <li>' +
+ ' <xsl:attribute name="class">' +
+ ' <xsl:if test="$is_last = true()">jstree-last </xsl:if>' +
+ ' <xsl:choose>' +
+ ' <xsl:when test="@state = \'open\'">jstree-open </xsl:when>' +
+ ' <xsl:when test="$children or @hasChildren or @state = \'closed\'">jstree-closed </xsl:when>' +
+ ' <xsl:otherwise>jstree-leaf </xsl:otherwise>' +
+ ' </xsl:choose>' +
+ ' <xsl:value-of select="@class" />' +
+ ' </xsl:attribute>' +
+ ' <xsl:for-each select="@*">' +
+ ' <xsl:if test="name() != \'parent_id\' and name() != \'hasChildren\' and name() != \'class\' and name() != \'state\'">' +
+ ' <xsl:attribute name="{name()}"><xsl:value-of select="." /></xsl:attribute>' +
+ ' </xsl:if>' +
+ ' </xsl:for-each>' +
+ ' <ins class="jstree-icon"><xsl:text>&#xa0;</xsl:text></ins>' +
+ ' <xsl:for-each select="content/name">' +
+ ' <a>' +
+ ' <xsl:attribute name="href">' +
+ ' <xsl:choose>' +
+ ' <xsl:when test="@href"><xsl:value-of select="@href" /></xsl:when>' +
+ ' <xsl:otherwise>#</xsl:otherwise>' +
+ ' </xsl:choose>' +
+ ' </xsl:attribute>' +
+ ' <xsl:attribute name="class"><xsl:value-of select="@lang" /> <xsl:value-of select="@class" /></xsl:attribute>' +
+ ' <xsl:attribute name="style"><xsl:value-of select="@style" /></xsl:attribute>' +
+ ' <xsl:for-each select="@*">' +
+ ' <xsl:if test="name() != \'style\' and name() != \'class\' and name() != \'href\'">' +
+ ' <xsl:attribute name="{name()}"><xsl:value-of select="." /></xsl:attribute>' +
+ ' </xsl:if>' +
+ ' </xsl:for-each>' +
+ ' <ins>' +
+ ' <xsl:attribute name="class">jstree-icon ' +
+ ' <xsl:if test="string-length(attribute::icon) > 0 and not(contains(@icon,\'/\'))"><xsl:value-of select="@icon" /></xsl:if>' +
+ ' </xsl:attribute>' +
+ ' <xsl:if test="string-length(attribute::icon) > 0 and contains(@icon,\'/\')"><xsl:attribute name="style">background:url(<xsl:value-of select="@icon" />) center center no-repeat;</xsl:attribute></xsl:if>' +
+ ' <xsl:text>&#xa0;</xsl:text>' +
+ ' </ins>' +
+ ' <xsl:value-of select="current()" />' +
+ ' </a>' +
+ ' </xsl:for-each>' +
+ ' <xsl:if test="$children">' +
+ ' <ul>' +
+ ' <xsl:for-each select="//item[@parent_id=$node/attribute::id]">' +
+ ' <xsl:call-template name="nodes">' +
+ ' <xsl:with-param name="node" select="." />' +
+ ' <xsl:with-param name="is_last" select="number(position() = last())" />' +
+ ' </xsl:call-template>' +
+ ' </xsl:for-each>' +
+ ' </ul>' +
+ ' </xsl:if>' +
+ ' </li>' +
+ '</xsl:template>' +
+ '</xsl:stylesheet>'
+ };
+ $.jstree.plugin("xml_data", {
+ defaults : {
+ data : false,
+ ajax : false,
+ xsl : "flat",
+ clean_node : false,
+ correct_state : true
+ },
+ _fn : {
+ load_node : function (obj, s_call, e_call) { var _this = this; this.load_node_xml(obj, function () { _this.__callback({ "obj" : obj }); s_call.call(this); }, e_call); },
+ _is_loaded : function (obj) {
+ var s = this._get_settings().xml_data;
+ obj = this._get_node(obj);
+ return obj == -1 || !obj || !s.ajax || obj.is(".jstree-open, .jstree-leaf") || obj.children("ul").children("li").size() > 0;
+ },
+ load_node_xml : function (obj, s_call, e_call) {
+ var s = this.get_settings().xml_data,
+ error_func = function () {},
+ success_func = function () {};
+
+ obj = this._get_node(obj);
+ if(obj && obj !== -1) {
+ if(obj.data("jstree-is-loading")) { return; }
+ else { obj.data("jstree-is-loading",true); }
+ }
+ switch(!0) {
+ case (!s.data && !s.ajax): throw "Neither data nor ajax settings supplied.";
+ case (!!s.data && !s.ajax) || (!!s.data && !!s.ajax && (!obj || obj === -1)):
+ if(!obj || obj == -1) {
+ this.parse_xml(s.data, $.proxy(function (d) {
+ if(d) {
+ d = d.replace(/ ?xmlns="[^"]*"/ig, "");
+ if(d.length > 10) {
+ d = $(d);
+ this.get_container().children("ul").empty().append(d.children());
+ if(s.clean_node) { this.clean_node(obj); }
+ if(s_call) { s_call.call(this); }
+ }
+ }
+ else {
+ if(s.correct_state) {
+ this.get_container().children("ul").empty();
+ if(s_call) { s_call.call(this); }
+ }
+ }
+ }, this));
+ }
+ break;
+ case (!s.data && !!s.ajax) || (!!s.data && !!s.ajax && obj && obj !== -1):
+ error_func = function (x, t, e) {
+ var ef = this.get_settings().xml_data.ajax.error;
+ if(ef) { ef.call(this, x, t, e); }
+ if(obj !== -1 && obj.length) {
+ obj.children(".jstree-loading").removeClass("jstree-loading");
+ obj.data("jstree-is-loading",false);
+ if(t === "success" && s.correct_state) { obj.removeClass("jstree-open jstree-closed").addClass("jstree-leaf"); }
+ }
+ else {
+ if(t === "success" && s.correct_state) { this.get_container().children("ul").empty(); }
+ }
+ if(e_call) { e_call.call(this); }
+ };
+ success_func = function (d, t, x) {
+ d = x.responseText;
+ var sf = this.get_settings().xml_data.ajax.success;
+ if(sf) { d = sf.call(this,d,t,x) || d; }
+ if(d == "") {
+ return error_func.call(this, x, t, "");
+ }
+ this.parse_xml(d, $.proxy(function (d) {
+ if(d) {
+ d = d.replace(/ ?xmlns="[^"]*"/ig, "");
+ if(d.length > 10) {
+ d = $(d);
+ if(obj === -1 || !obj) { this.get_container().children("ul").empty().append(d.children()); }
+ else { obj.children(".jstree-loading").removeClass("jstree-loading"); obj.append(d); obj.data("jstree-is-loading",false); }
+ if(s.clean_node) { this.clean_node(obj); }
+ if(s_call) { s_call.call(this); }
+ }
+ else {
+ if(obj && obj !== -1) {
+ obj.children(".jstree-loading").removeClass("jstree-loading");
+ obj.data("jstree-is-loading",false);
+ if(s.correct_state) {
+ obj.removeClass("jstree-open jstree-closed").addClass("jstree-leaf");
+ if(s_call) { s_call.call(this); }
+ }
+ }
+ else {
+ if(s.correct_state) {
+ this.get_container().children("ul").empty();
+ if(s_call) { s_call.call(this); }
+ }
+ }
+ }
+ }
+ }, this));
+ };
+ s.ajax.context = this;
+ s.ajax.error = error_func;
+ s.ajax.success = success_func;
+ if(!s.ajax.dataType) { s.ajax.dataType = "xml"; }
+ if($.isFunction(s.ajax.url)) { s.ajax.url = s.ajax.url.call(this, obj); }
+ if($.isFunction(s.ajax.data)) { s.ajax.data = s.ajax.data.call(this, obj); }
+ $.ajax(s.ajax);
+ break;
+ }
+ },
+ parse_xml : function (xml, callback) {
+ var s = this._get_settings().xml_data;
+ $.vakata.xslt(xml, xsl[s.xsl], callback);
+ },
+ get_xml : function (tp, obj, li_attr, a_attr, is_callback) {
+ var result = "",
+ s = this._get_settings(),
+ _this = this,
+ tmp1, tmp2, li, a, lang;
+ if(!tp) { tp = "flat"; }
+ if(!is_callback) { is_callback = 0; }
+ obj = this._get_node(obj);
+ if(!obj || obj === -1) { obj = this.get_container().find("> ul > li"); }
+ li_attr = $.isArray(li_attr) ? li_attr : [ "id", "class" ];
+ if(!is_callback && this.data.types && $.inArray(s.types.type_attr, li_attr) === -1) { li_attr.push(s.types.type_attr); }
+
+ a_attr = $.isArray(a_attr) ? a_attr : [ ];
+
+ if(!is_callback) { result += "<root>"; }
+ obj.each(function () {
+ result += "<item";
+ li = $(this);
+ $.each(li_attr, function (i, v) { result += " " + v + "=\"" + (li.attr(v) || "").replace(/jstree[^ ]*|$/ig,'').replace(/^\s+$/ig,"") + "\""; });
+ if(li.hasClass("jstree-open")) { result += " state=\"open\""; }
+ if(li.hasClass("jstree-closed")) { result += " state=\"closed\""; }
+ if(tp === "flat") { result += " parent_id=\"" + is_callback + "\""; }
+ result += ">";
+ result += "<content>";
+ a = li.children("a");
+ a.each(function () {
+ tmp1 = $(this);
+ lang = false;
+ result += "<name";
+ if($.inArray("languages", s.plugins) !== -1) {
+ $.each(s.languages, function (k, z) {
+ if(tmp1.hasClass(z)) { result += " lang=\"" + z + "\""; lang = z; return false; }
+ });
+ }
+ if(a_attr.length) {
+ $.each(a_attr, function (k, z) {
+ result += " " + z + "=\"" + (tmp1.attr(z) || "").replace(/jstree[^ ]*|$/ig,'') + "\"";
+ });
+ }
+ if(tmp1.children("ins").get(0).className.replace(/jstree[^ ]*|$/ig,'').replace(/^\s+$/ig,"").length) {
+ result += ' icon="' + tmp1.children("ins").get(0).className.replace(/jstree[^ ]*|$/ig,'').replace(/^\s+$/ig,"") + '"';
+ }
+ if(tmp1.children("ins").get(0).style.backgroundImage.length) {
+ result += ' icon="' + tmp1.children("ins").get(0).style.backgroundImage.replace("url(","").replace(")","") + '"';
+ }
+ result += ">";
+ result += "<![CDATA[" + _this.get_text(tmp1, lang) + "]]>";
+ result += "</name>";
+ });
+ result += "</content>";
+ tmp2 = li[0].id;
+ li = li.find("> ul > li");
+ if(li.length) { tmp2 = _this.get_xml(tp, li, li_attr, a_attr, tmp2); }
+ else { tmp2 = ""; }
+ if(tp == "nest") { result += tmp2; }
+ result += "</item>";
+ if(tp == "flat") { result += tmp2; }
+ });
+ if(!is_callback) { result += "</root>"; }
+ return result;
+ }
+ }
+ });
+})(jQuery);
+//*/
+
+/*
+ * jsTree search plugin 1.0
+ * Enables both sync and async search on the tree
+ * DOES NOT WORK WITH JSON PROGRESSIVE RENDER
+ */
+(function ($) {
+ $.expr[':'].jstree_contains = function(a,i,m){
+ return (a.textContent || a.innerText || "").toLowerCase().indexOf(m[3].toLowerCase())>=0;
+ };
+ $.jstree.plugin("search", {
+ __init : function () {
+ this.data.search.str = "";
+ this.data.search.result = $();
+ },
+ defaults : {
+ ajax : false, // OR ajax object
+ case_insensitive : false
+ },
+ _fn : {
+ search : function (str, skip_async) {
+ if(str === "") { return; }
+ var s = this.get_settings().search,
+ t = this,
+ error_func = function () { },
+ success_func = function () { };
+ this.data.search.str = str;
+
+ if(!skip_async && s.ajax !== false && this.get_container().find(".jstree-closed:eq(0)").length > 0) {
+ this.search.supress_callback = true;
+ error_func = function () { };
+ success_func = function (d, t, x) {
+ var sf = this.get_settings().search.ajax.success;
+ if(sf) { d = sf.call(this,d,t,x) || d; }
+ this.data.search.to_open = d;
+ this._search_open();
+ };
+ s.ajax.context = this;
+ s.ajax.error = error_func;
+ s.ajax.success = success_func;
+ if($.isFunction(s.ajax.url)) { s.ajax.url = s.ajax.url.call(this, str); }
+ if($.isFunction(s.ajax.data)) { s.ajax.data = s.ajax.data.call(this, str); }
+ if(!s.ajax.data) { s.ajax.data = { "search_string" : str }; }
+ if(!s.ajax.dataType || /^json/.exec(s.ajax.dataType)) { s.ajax.dataType = "json"; }
+ $.ajax(s.ajax);
+ return;
+ }
+ if(this.data.search.result.length) { this.clear_search(); }
+ this.data.search.result = this.get_container().find("a" + (this.data.languages ? "." + this.get_lang() : "" ) + ":" + (s.case_insensitive ? "jstree_contains" : "contains") + "(" + this.data.search.str + ")");
+ this.data.search.result.addClass("jstree-search").parents(".jstree-closed").each(function () {
+ t.open_node(this, false, true);
+ });
+ this.__callback({ nodes : this.data.search.result, str : str });
+ },
+ clear_search : function (str) {
+ this.data.search.result.removeClass("jstree-search");
+ this.__callback(this.data.search.result);
+ this.data.search.result = $();
+ },
+ _search_open : function (is_callback) {
+ var _this = this,
+ done = true,
+ current = [],
+ remaining = [];
+ if(this.data.search.to_open.length) {
+ $.each(this.data.search.to_open, function (i, val) {
+ if(val == "#") { return true; }
+ if($(val).length && $(val).is(".jstree-closed")) { current.push(val); }
+ else { remaining.push(val); }
+ });
+ if(current.length) {
+ this.data.search.to_open = remaining;
+ $.each(current, function (i, val) {
+ _this.open_node(val, function () { _this._search_open(true); });
+ });
+ done = false;
+ }
+ }
+ if(done) { this.search(this.data.search.str, true); }
+ }
+ }
+ });
+})(jQuery);
+//*/
+
+/*
+ * jsTree contextmenu plugin 1.0
+ */
+(function ($) {
+ $.vakata.context = {
+ cnt : $("<div id='vakata-contextmenu'/>"),
+ vis : false,
+ tgt : false,
+ par : false,
+ func : false,
+ data : false,
+ show : function (s, t, x, y, d, p) {
+ var html = $.vakata.context.parse(s), h, w;
+ if(!html) { return; }
+ $.vakata.context.vis = true;
+ $.vakata.context.tgt = t;
+ $.vakata.context.par = p || t || null;
+ $.vakata.context.data = d || null;
+ $.vakata.context.cnt
+ .html(html)
+ .css({ "visibility" : "hidden", "display" : "block", "left" : 0, "top" : 0 });
+ h = $.vakata.context.cnt.height();
+ w = $.vakata.context.cnt.width();
+ if(x + w > $(document).width()) {
+ x = $(document).width() - (w + 5);
+ $.vakata.context.cnt.find("li > ul").addClass("right");
+ }
+ if(y + h > $(document).height()) {
+ y = y - (h + t[0].offsetHeight);
+ $.vakata.context.cnt.find("li > ul").addClass("bottom");
+ }
+
+ $.vakata.context.cnt
+ .css({ "left" : x, "top" : y })
+ .find("li:has(ul)")
+ .bind("mouseenter", function (e) {
+ var w = $(document).width(),
+ h = $(document).height(),
+ ul = $(this).children("ul").show();
+ if(w !== $(document).width()) { ul.toggleClass("right"); }
+ if(h !== $(document).height()) { ul.toggleClass("bottom"); }
+ })
+ .bind("mouseleave", function (e) {
+ $(this).children("ul").hide();
+ })
+ .end()
+ .css({ "visibility" : "visible" })
+ .show();
+ $(document).triggerHandler("context_show.vakata");
+ },
+ hide : function () {
+ $.vakata.context.vis = false;
+ $.vakata.context.cnt.attr("class","").hide();
+ $(document).triggerHandler("context_hide.vakata");
+ },
+ parse : function (s, is_callback) {
+ if(!s) { return false; }
+ var str = "",
+ tmp = false,
+ was_sep = true;
+ if(!is_callback) { $.vakata.context.func = {}; }
+ str += "<ul>";
+ $.each(s, function (i, val) {
+ if(!val) { return true; }
+ $.vakata.context.func[i] = val.action;
+ if(!was_sep && val.separator_before) {
+ str += "<li class='vakata-separator vakata-separator-before'></li>";
+ }
+ was_sep = false;
+ str += "<li class='" + (val._class || "") + (val._disabled ? " jstree-contextmenu-disabled " : "") + "'><ins ";
+ if(val.icon && val.icon.indexOf("/") === -1) { str += " class='" + val.icon + "' "; }
+ if(val.icon && val.icon.indexOf("/") !== -1) { str += " style='background:url(" + val.icon + ") center center no-repeat;' "; }
+ str += ">&#160;</ins><a href='#' rel='" + i + "'>";
+ if(val.submenu) {
+ str += "<span style='float:right;'>&raquo;</span>";
+ }
+ str += val.label + "</a>";
+ if(val.submenu) {
+ tmp = $.vakata.context.parse(val.submenu, true);
+ if(tmp) { str += tmp; }
+ }
+ str += "</li>";
+ if(val.separator_after) {
+ str += "<li class='vakata-separator vakata-separator-after'></li>";
+ was_sep = true;
+ }
+ });
+ str = str.replace(/<li class\='vakata-separator vakata-separator-after'\><\/li\>$/,"");
+ str += "</ul>";
+ return str.length > 10 ? str : false;
+ },
+ exec : function (i) {
+ if($.isFunction($.vakata.context.func[i])) {
+ $.vakata.context.func[i].call($.vakata.context.data, $.vakata.context.par);
+ return true;
+ }
+ else { return false; }
+ }
+ };
+ $(function () {
+ var css_string = '' +
+ '#vakata-contextmenu { display:none; position:absolute; margin:0; padding:0; min-width:180px; background:#ebebeb; border:1px solid silver; z-index:10000; *width:180px; } ' +
+ '#vakata-contextmenu ul { min-width:180px; *width:180px; } ' +
+ '#vakata-contextmenu ul, #vakata-contextmenu li { margin:0; padding:0; list-style-type:none; display:block; } ' +
+ '#vakata-contextmenu li { line-height:20px; min-height:20px; position:relative; padding:0px; } ' +
+ '#vakata-contextmenu li a { padding:1px 6px; line-height:17px; display:block; text-decoration:none; margin:1px 1px 0 1px; } ' +
+ '#vakata-contextmenu li ins { float:left; width:16px; height:16px; text-decoration:none; margin-right:2px; } ' +
+ '#vakata-contextmenu li a:hover, #vakata-contextmenu li.vakata-hover > a { background:gray; color:white; } ' +
+ '#vakata-contextmenu li ul { display:none; position:absolute; top:-2px; left:100%; background:#ebebeb; border:1px solid gray; } ' +
+ '#vakata-contextmenu .right { right:100%; left:auto; } ' +
+ '#vakata-contextmenu .bottom { bottom:-1px; top:auto; } ' +
+ '#vakata-contextmenu li.vakata-separator { min-height:0; height:1px; line-height:1px; font-size:1px; overflow:hidden; margin:0 2px; background:silver; /* border-top:1px solid #fefefe; */ padding:0; } ';
+ $.vakata.css.add_sheet({ str : css_string });
+ $.vakata.context.cnt
+ .delegate("a","click", function (e) { e.preventDefault(); })
+ .delegate("a","mouseup", function (e) {
+ if(!$(this).parent().hasClass("jstree-contextmenu-disabled") && $.vakata.context.exec($(this).attr("rel"))) {
+ $.vakata.context.hide();
+ }
+ else { $(this).blur(); }
+ })
+ .delegate("a","mouseover", function () {
+ $.vakata.context.cnt.find(".vakata-hover").removeClass("vakata-hover");
+ })
+ .appendTo("body");
+ $(document).bind("mousedown", function (e) { if($.vakata.context.vis && !$.contains($.vakata.context.cnt[0], e.target)) { $.vakata.context.hide(); } });
+ if(typeof $.hotkeys !== "undefined") {
+ $(document)
+ .bind("keydown", "up", function (e) {
+ if($.vakata.context.vis) {
+ var o = $.vakata.context.cnt.find("ul:visible").last().children(".vakata-hover").removeClass("vakata-hover").prevAll("li:not(.vakata-separator)").first();
+ if(!o.length) { o = $.vakata.context.cnt.find("ul:visible").last().children("li:not(.vakata-separator)").last(); }
+ o.addClass("vakata-hover");
+ e.stopImmediatePropagation();
+ e.preventDefault();
+ }
+ })
+ .bind("keydown", "down", function (e) {
+ if($.vakata.context.vis) {
+ var o = $.vakata.context.cnt.find("ul:visible").last().children(".vakata-hover").removeClass("vakata-hover").nextAll("li:not(.vakata-separator)").first();
+ if(!o.length) { o = $.vakata.context.cnt.find("ul:visible").last().children("li:not(.vakata-separator)").first(); }
+ o.addClass("vakata-hover");
+ e.stopImmediatePropagation();
+ e.preventDefault();
+ }
+ })
+ .bind("keydown", "right", function (e) {
+ if($.vakata.context.vis) {
+ $.vakata.context.cnt.find(".vakata-hover").children("ul").show().children("li:not(.vakata-separator)").removeClass("vakata-hover").first().addClass("vakata-hover");
+ e.stopImmediatePropagation();
+ e.preventDefault();
+ }
+ })
+ .bind("keydown", "left", function (e) {
+ if($.vakata.context.vis) {
+ $.vakata.context.cnt.find(".vakata-hover").children("ul").hide().children(".vakata-separator").removeClass("vakata-hover");
+ e.stopImmediatePropagation();
+ e.preventDefault();
+ }
+ })
+ .bind("keydown", "esc", function (e) {
+ $.vakata.context.hide();
+ e.preventDefault();
+ })
+ .bind("keydown", "space", function (e) {
+ $.vakata.context.cnt.find(".vakata-hover").last().children("a").click();
+ e.preventDefault();
+ });
+ }
+ });
+
+ $.jstree.plugin("contextmenu", {
+ __init : function () {
+ this.get_container()
+ .delegate("a", "contextmenu.jstree", $.proxy(function (e) {
+ e.preventDefault();
+ this.show_contextmenu(e.currentTarget, e.pageX, e.pageY);
+ }, this))
+ .bind("destroy.jstree", $.proxy(function () {
+ if(this.data.contextmenu) {
+ $.vakata.context.hide();
+ }
+ }, this));
+ $(document).bind("context_hide.vakata", $.proxy(function () { this.data.contextmenu = false; }, this));
+ },
+ defaults : {
+ select_node : false, // requires UI plugin
+ show_at_node : true,
+ items : { // Could be a function that should return an object like this one
+ "create" : {
+ "separator_before" : false,
+ "separator_after" : true,
+ "label" : "Create",
+ "action" : function (obj) { this.create(obj); }
+ },
+ "rename" : {
+ "separator_before" : false,
+ "separator_after" : false,
+ "label" : "Rename",
+ "action" : function (obj) { this.rename(obj); }
+ },
+ "remove" : {
+ "separator_before" : false,
+ "icon" : false,
+ "separator_after" : false,
+ "label" : "Delete",
+ "action" : function (obj) { this.remove(obj); }
+ },
+ "ccp" : {
+ "separator_before" : true,
+ "icon" : false,
+ "separator_after" : false,
+ "label" : "Edit",
+ "action" : false,
+ "submenu" : {
+ "cut" : {
+ "separator_before" : false,
+ "separator_after" : false,
+ "label" : "Cut",
+ "action" : function (obj) { this.cut(obj); }
+ },
+ "copy" : {
+ "separator_before" : false,
+ "icon" : false,
+ "separator_after" : false,
+ "label" : "Copy",
+ "action" : function (obj) { this.copy(obj); }
+ },
+ "paste" : {
+ "separator_before" : false,
+ "icon" : false,
+ "separator_after" : false,
+ "label" : "Paste",
+ "action" : function (obj) { this.paste(obj); }
+ }
+ }
+ }
+ }
+ },
+ _fn : {
+ show_contextmenu : function (obj, x, y) {
+ obj = this._get_node(obj);
+ var s = this.get_settings().contextmenu,
+ a = obj.children("a:visible:eq(0)"),
+ o = false;
+ if(s.select_node && this.data.ui && !this.is_selected(obj)) {
+ this.deselect_all();
+ this.select_node(obj, true);
+ }
+ if(s.show_at_node || typeof x === "undefined" || typeof y === "undefined") {
+ o = a.offset();
+ x = o.left;
+ y = o.top + this.data.core.li_height;
+ }
+ if($.isFunction(s.items)) { s.items = s.items.call(this, obj); }
+ this.data.contextmenu = true;
+ $.vakata.context.show(s.items, a, x, y, this, obj);
+ if(this.data.themes) { $.vakata.context.cnt.attr("class", "jstree-" + this.data.themes.theme + "-context"); }
+ }
+ }
+ });
+})(jQuery);
+//*/
+
+/*
+ * jsTree types plugin 1.0
+ * Adds support types of nodes
+ * You can set an attribute on each li node, that represents its type.
+ * According to the type setting the node may get custom icon/validation rules
+ */
+(function ($) {
+ $.jstree.plugin("types", {
+ __init : function () {
+ var s = this._get_settings().types;
+ this.data.types.attach_to = [];
+ this.get_container()
+ .bind("init.jstree", $.proxy(function () {
+ var types = s.types,
+ attr = s.type_attr,
+ icons_css = "",
+ _this = this;
+
+ $.each(types, function (i, tp) {
+ $.each(tp, function (k, v) {
+ if(!/^(max_depth|max_children|icon|valid_children)$/.test(k)) { _this.data.types.attach_to.push(k); }
+ });
+ if(!tp.icon) { return true; }
+ if( tp.icon.image || tp.icon.position) {
+ if(i == "default") { icons_css += '.jstree-' + _this.get_index() + ' a > .jstree-icon { '; }
+ else { icons_css += '.jstree-' + _this.get_index() + ' li[' + attr + '=' + i + '] > a > .jstree-icon { '; }
+ if(tp.icon.image) { icons_css += ' background-image:url(' + tp.icon.image + '); '; }
+ if(tp.icon.position){ icons_css += ' background-position:' + tp.icon.position + '; '; }
+ else { icons_css += ' background-position:0 0; '; }
+ icons_css += '} ';
+ }
+ });
+ if(icons_css != "") { $.vakata.css.add_sheet({ 'str' : icons_css }); }
+ }, this))
+ .bind("before.jstree", $.proxy(function (e, data) {
+ if($.inArray(data.func, this.data.types.attach_to) !== -1) {
+ var s = this._get_settings().types.types,
+ t = this._get_type(data.args[0]);
+ if(
+ (
+ (s[t] && typeof s[t][data.func] !== "undefined") ||
+ (s["default"] && typeof s["default"][data.func] !== "undefined")
+ ) && !this._check(data.func, data.args[0])
+ ) {
+ e.stopImmediatePropagation();
+ return false;
+ }
+ }
+ }, this));
+ },
+ defaults : {
+ // defines maximum number of root nodes (-1 means unlimited, -2 means disable max_children checking)
+ max_children : -1,
+ // defines the maximum depth of the tree (-1 means unlimited, -2 means disable max_depth checking)
+ max_depth : -1,
+ // defines valid node types for the root nodes
+ valid_children : "all",
+
+ // where is the type stores (the rel attribute of the LI element)
+ type_attr : "rel",
+ // a list of types
+ types : {
+ // the default type
+ "default" : {
+ "max_children" : -1,
+ "max_depth" : -1,
+ "valid_children": "all"
+
+ // Bound functions - you can bind any other function here (using boolean or function)
+ //"select_node" : true,
+ //"open_node" : true,
+ //"close_node" : true,
+ //"create_node" : true,
+ //"delete_node" : true
+ }
+ }
+ },
+ _fn : {
+ _get_type : function (obj) {
+ obj = this._get_node(obj);
+ return (!obj || !obj.length) ? false : obj.attr(this._get_settings().types.type_attr) || "default";
+ },
+ set_type : function (str, obj) {
+ obj = this._get_node(obj);
+ return (!obj.length || !str) ? false : obj.attr(this._get_settings().types.type_attr, str);
+ },
+ _check : function (rule, obj, opts) {
+ var v = false, t = this._get_type(obj), d = 0, _this = this, s = this._get_settings().types;
+ if(obj === -1) {
+ if(!!s[rule]) { v = s[rule]; }
+ else { return; }
+ }
+ else {
+ if(t === false) { return; }
+ if(!!s.types[t] && !!s.types[t][rule]) { v = s.types[t][rule]; }
+ else if(!!s.types["default"] && !!s.types["default"][rule]) { v = s.types["default"][rule]; }
+ }
+ if($.isFunction(v)) { v = v.call(this, obj); }
+ if(rule === "max_depth" && obj !== -1 && opts !== false && s.max_depth !== -2 && v !== 0) {
+ // also include the node itself - otherwise if root node it is not checked
+ this._get_node(obj).children("a:eq(0)").parentsUntil(".jstree","li").each(function (i) {
+ // check if current depth already exceeds global tree depth
+ if(s.max_depth !== -1 && s.max_depth - (i + 1) <= 0) { v = 0; return false; }
+ d = (i === 0) ? v : _this._check(rule, this, false);
+ // check if current node max depth is already matched or exceeded
+ if(d !== -1 && d - (i + 1) <= 0) { v = 0; return false; }
+ // otherwise - set the max depth to the current value minus current depth
+ if(d >= 0 && (d - (i + 1) < v || v < 0) ) { v = d - (i + 1); }
+ // if the global tree depth exists and it minus the nodes calculated so far is less than `v` or `v` is unlimited
+ if(s.max_depth >= 0 && (s.max_depth - (i + 1) < v || v < 0) ) { v = s.max_depth - (i + 1); }
+ });
+ }
+ return v;
+ },
+ check_move : function () {
+ if(!this.__call_old()) { return false; }
+ var m = this._get_move(),
+ s = m.rt._get_settings().types,
+ mc = m.rt._check("max_children", m.cr),
+ md = m.rt._check("max_depth", m.cr),
+ vc = m.rt._check("valid_children", m.cr),
+ ch = 0, d = 1, t;
+
+ if(vc === "none") { return false; }
+ if($.isArray(vc) && m.ot && m.ot._get_type) {
+ m.o.each(function () {
+ if($.inArray(m.ot._get_type(this), vc) === -1) { d = false; return false; }
+ });
+ if(d === false) { return false; }
+ }
+ if(s.max_children !== -2 && mc !== -1) {
+ ch = m.cr === -1 ? this.get_container().children("> ul > li").not(m.o).length : m.cr.children("> ul > li").not(m.o).length;
+ if(ch + m.o.length > mc) { return false; }
+ }
+ if(s.max_depth !== -2 && md !== -1) {
+ d = 0;
+ if(md === 0) { return false; }
+ if(typeof m.o.d === "undefined") {
+ // TODO: deal with progressive rendering and async when checking max_depth (how to know the depth of the moved node)
+ t = m.o;
+ while(t.length > 0) {
+ t = t.find("> ul > li");
+ d ++;
+ }
+ m.o.d = d;
+ }
+ if(md - m.o.d < 0) { return false; }
+ }
+ return true;
+ },
+ create_node : function (obj, position, js, callback, is_loaded, skip_check) {
+ if(!skip_check && (is_loaded || this._is_loaded(obj))) {
+ var p = (position && position.match(/^before|after$/i) && obj !== -1) ? this._get_parent(obj) : this._get_node(obj),
+ s = this._get_settings().types,
+ mc = this._check("max_children", p),
+ md = this._check("max_depth", p),
+ vc = this._check("valid_children", p),
+ ch;
+ if(!js) { js = {}; }
+ if(vc === "none") { return false; }
+ if($.isArray(vc)) {
+ if(!js.attr || !js.attr[s.type_attr]) {
+ if(!js.attr) { js.attr = {}; }
+ js.attr[s.type_attr] = vc[0];
+ }
+ else {
+ if($.inArray(js.attr[s.type_attr], vc) === -1) { return false; }
+ }
+ }
+ if(s.max_children !== -2 && mc !== -1) {
+ ch = p === -1 ? this.get_container().children("> ul > li").length : p.children("> ul > li").length;
+ if(ch + 1 > mc) { return false; }
+ }
+ if(s.max_depth !== -2 && md !== -1 && (md - 1) < 0) { return false; }
+ }
+ return this.__call_old(true, obj, position, js, callback, is_loaded, skip_check);
+ }
+ }
+ });
+})(jQuery);
+//*/
+
+/*
+ * jsTree HTML data 1.0
+ * The HTML data store. Datastores are build by replacing the `load_node` and `_is_loaded` functions.
+ */
+(function ($) {
+ $.jstree.plugin("html_data", {
+ __init : function () {
+ // this used to use html() and clean the whitespace, but this way any attached data was lost
+ this.data.html_data.original_container_html = this.get_container().find(" > ul > li").clone(true);
+ // remove white space from LI node - otherwise nodes appear a bit to the right
+ this.data.html_data.original_container_html.find("li").andSelf().contents().filter(function() { return this.nodeType == 3; }).remove();
+ },
+ defaults : {
+ data : false,
+ ajax : false,
+ correct_state : true
+ },
+ _fn : {
+ load_node : function (obj, s_call, e_call) { var _this = this; this.load_node_html(obj, function () { _this.__callback({ "obj" : obj }); s_call.call(this); }, e_call); },
+ _is_loaded : function (obj) {
+ obj = this._get_node(obj);
+ return obj == -1 || !obj || !this._get_settings().html_data.ajax || obj.is(".jstree-open, .jstree-leaf") || obj.children("ul").children("li").size() > 0;
+ },
+ load_node_html : function (obj, s_call, e_call) {
+ var d,
+ s = this.get_settings().html_data,
+ error_func = function () {},
+ success_func = function () {};
+ obj = this._get_node(obj);
+ if(obj && obj !== -1) {
+ if(obj.data("jstree-is-loading")) { return; }
+ else { obj.data("jstree-is-loading",true); }
+ }
+ switch(!0) {
+ case (!s.data && !s.ajax):
+ if(!obj || obj == -1) {
+ this.get_container()
+ .children("ul").empty()
+ .append(this.data.html_data.original_container_html)
+ .find("li, a").filter(function () { return this.firstChild.tagName !== "INS"; }).prepend("<ins class='jstree-icon'>&#160;</ins>").end()
+ .filter("a").children("ins:first-child").not(".jstree-icon").addClass("jstree-icon");
+ this.clean_node();
+ }
+ if(s_call) { s_call.call(this); }
+ break;
+ case (!!s.data && !s.ajax) || (!!s.data && !!s.ajax && (!obj || obj === -1)):
+ if(!obj || obj == -1) {
+ d = $(s.data);
+ if(!d.is("ul")) { d = $("<ul>").append(d); }
+ this.get_container()
+ .children("ul").empty().append(d.children())
+ .find("li, a").filter(function () { return this.firstChild.tagName !== "INS"; }).prepend("<ins class='jstree-icon'>&#160;</ins>").end()
+ .filter("a").children("ins:first-child").not(".jstree-icon").addClass("jstree-icon");
+ this.clean_node();
+ }
+ if(s_call) { s_call.call(this); }
+ break;
+ case (!s.data && !!s.ajax) || (!!s.data && !!s.ajax && obj && obj !== -1):
+ obj = this._get_node(obj);
+ error_func = function (x, t, e) {
+ var ef = this.get_settings().html_data.ajax.error;
+ if(ef) { ef.call(this, x, t, e); }
+ if(obj != -1 && obj.length) {
+ obj.children(".jstree-loading").removeClass("jstree-loading");
+ obj.data("jstree-is-loading",false);
+ if(t === "success" && s.correct_state) { obj.removeClass("jstree-open jstree-closed").addClass("jstree-leaf"); }
+ }
+ else {
+ if(t === "success" && s.correct_state) { this.get_container().children("ul").empty(); }
+ }
+ if(e_call) { e_call.call(this); }
+ };
+ success_func = function (d, t, x) {
+ var sf = this.get_settings().html_data.ajax.success;
+ if(sf) { d = sf.call(this,d,t,x) || d; }
+ if(d == "") {
+ return error_func.call(this, x, t, "");
+ }
+ if(d) {
+ d = $(d);
+ if(!d.is("ul")) { d = $("<ul>").append(d); }
+ if(obj == -1 || !obj) { this.get_container().children("ul").empty().append(d.children()).find("li, a").filter(function () { return this.firstChild.tagName !== "INS"; }).prepend("<ins class='jstree-icon'>&#160;</ins>").end().filter("a").children("ins:first-child").not(".jstree-icon").addClass("jstree-icon"); }
+ else { obj.children(".jstree-loading").removeClass("jstree-loading"); obj.append(d).find("li, a").filter(function () { return this.firstChild.tagName !== "INS"; }).prepend("<ins class='jstree-icon'>&#160;</ins>").end().filter("a").children("ins:first-child").not(".jstree-icon").addClass("jstree-icon"); obj.data("jstree-is-loading",false); }
+ this.clean_node(obj);
+ if(s_call) { s_call.call(this); }
+ }
+ else {
+ if(obj && obj !== -1) {
+ obj.children(".jstree-loading").removeClass("jstree-loading");
+ obj.data("jstree-is-loading",false);
+ if(s.correct_state) {
+ obj.removeClass("jstree-open jstree-closed").addClass("jstree-leaf");
+ if(s_call) { s_call.call(this); }
+ }
+ }
+ else {
+ if(s.correct_state) {
+ this.get_container().children("ul").empty();
+ if(s_call) { s_call.call(this); }
+ }
+ }
+ }
+ };
+ s.ajax.context = this;
+ s.ajax.error = error_func;
+ s.ajax.success = success_func;
+ if(!s.ajax.dataType) { s.ajax.dataType = "html"; }
+ if($.isFunction(s.ajax.url)) { s.ajax.url = s.ajax.url.call(this, obj); }
+ if($.isFunction(s.ajax.data)) { s.ajax.data = s.ajax.data.call(this, obj); }
+ $.ajax(s.ajax);
+ break;
+ }
+ }
+ }
+ });
+ // include the HTML data plugin by default
+ $.jstree.defaults.plugins.push("html_data");
+})(jQuery);
+//*/
+
+/*
+ * jsTree themeroller plugin 1.0
+ * Adds support for jQuery UI themes. Include this at the end of your plugins list, also make sure "themes" is not included.
+ */
+(function ($) {
+ $.jstree.plugin("themeroller", {
+ __init : function () {
+ var s = this._get_settings().themeroller;
+ this.get_container()
+ .addClass("ui-widget-content")
+ .delegate("a","mouseenter.jstree", function () {
+ $(this).addClass(s.item_h);
+ })
+ .delegate("a","mouseleave.jstree", function () {
+ $(this).removeClass(s.item_h);
+ })
+ .bind("open_node.jstree create_node.jstree", $.proxy(function (e, data) {
+ this._themeroller(data.rslt.obj);
+ }, this))
+ .bind("loaded.jstree refresh.jstree", $.proxy(function (e) {
+ this._themeroller();
+ }, this))
+ .bind("close_node.jstree", $.proxy(function (e, data) {
+ data.rslt.obj.children("ins").removeClass(s.opened).addClass(s.closed);
+ }, this))
+ .bind("select_node.jstree", $.proxy(function (e, data) {
+ data.rslt.obj.children("a").addClass(s.item_a);
+ }, this))
+ .bind("deselect_node.jstree deselect_all.jstree", $.proxy(function (e, data) {
+ this.get_container()
+ .find("." + s.item_a).removeClass(s.item_a).end()
+ .find(".jstree-clicked").addClass(s.item_a);
+ }, this))
+ .bind("move_node.jstree", $.proxy(function (e, data) {
+ this._themeroller(data.rslt.o);
+ }, this));
+ },
+ __destroy : function () {
+ var s = this._get_settings().themeroller,
+ c = [ "ui-icon" ];
+ $.each(s, function (i, v) {
+ v = v.split(" ");
+ if(v.length) { c = c.concat(v); }
+ });
+ this.get_container()
+ .removeClass("ui-widget-content")
+ .find("." + c.join(", .")).removeClass(c.join(" "));
+ },
+ _fn : {
+ _themeroller : function (obj) {
+ var s = this._get_settings().themeroller;
+ obj = !obj || obj == -1 ? this.get_container() : this._get_node(obj).parent();
+ obj
+ .find("li.jstree-closed > ins.jstree-icon").removeClass(s.opened).addClass("ui-icon " + s.closed).end()
+ .find("li.jstree-open > ins.jstree-icon").removeClass(s.closed).addClass("ui-icon " + s.opened).end()
+ .find("a").addClass(s.item)
+ .children("ins.jstree-icon").addClass("ui-icon " + s.item_icon);
+ }
+ },
+ defaults : {
+ "opened" : "ui-icon-triangle-1-se",
+ "closed" : "ui-icon-triangle-1-e",
+ "item" : "ui-state-default",
+ "item_h" : "ui-state-hover",
+ "item_a" : "ui-state-active",
+ "item_icon" : "ui-icon-folder-collapsed"
+ }
+ });
+ $(function() {
+ var css_string = '.jstree .ui-icon { overflow:visible; } .jstree a { padding:0 2px; }';
+ $.vakata.css.add_sheet({ str : css_string });
+ });
+})(jQuery);
+//*/
+
+/*
+ * jsTree unique plugin 1.0
+ * Forces different names amongst siblings (still a bit experimental)
+ * NOTE: does not check language versions (it will not be possible to have nodes with the same title, even in different languages)
+ */
+(function ($) {
+ $.jstree.plugin("unique", {
+ __init : function () {
+ this.get_container()
+ .bind("before.jstree", $.proxy(function (e, data) {
+ var nms = [], res = true, p, t;
+ if(data.func == "move_node") {
+ // obj, ref, position, is_copy, is_prepared, skip_check
+ if(data.args[4] === true) {
+ if(data.args[0].o && data.args[0].o.length) {
+ data.args[0].o.children("a").each(function () { nms.push($(this).text().replace(/^\s+/g,"")); });
+ res = this._check_unique(nms, data.args[0].np.find("> ul > li").not(data.args[0].o));
+ }
+ }
+ }
+ if(data.func == "create_node") {
+ // obj, position, js, callback, is_loaded
+ if(data.args[4] || this._is_loaded(data.args[0])) {
+ p = this._get_node(data.args[0]);
+ if(data.args[1] && (data.args[1] === "before" || data.args[1] === "after")) {
+ p = this._get_parent(data.args[0]);
+ if(!p || p === -1) { p = this.get_container(); }
+ }
+ if(typeof data.args[2] === "string") { nms.push(data.args[2]); }
+ else if(!data.args[2] || !data.args[2].data) { nms.push(this._get_settings().core.strings.new_node); }
+ else { nms.push(data.args[2].data); }
+ res = this._check_unique(nms, p.find("> ul > li"));
+ }
+ }
+ if(data.func == "rename_node") {
+ // obj, val
+ nms.push(data.args[1]);
+ t = this._get_node(data.args[0]);
+ p = this._get_parent(t);
+ if(!p || p === -1) { p = this.get_container(); }
+ res = this._check_unique(nms, p.find("> ul > li").not(t));
+ }
+ if(!res) {
+ e.stopPropagation();
+ return false;
+ }
+ }, this));
+ },
+ _fn : {
+ _check_unique : function (nms, p) {
+ var cnms = [];
+ p.children("a").each(function () { cnms.push($(this).text().replace(/^\s+/g,"")); });
+ if(!cnms.length || !nms.length) { return true; }
+ cnms = cnms.sort().join(",,").replace(/(,|^)([^,]+)(,,\2)+(,|$)/g,"$1$2$4").replace(/,,+/g,",").replace(/,$/,"").split(",");
+ if((cnms.length + nms.length) != cnms.concat(nms).sort().join(",,").replace(/(,|^)([^,]+)(,,\2)+(,|$)/g,"$1$2$4").replace(/,,+/g,",").replace(/,$/,"").split(",").length) {
+ return false;
+ }
+ return true;
+ },
+ check_move : function () {
+ if(!this.__call_old()) { return false; }
+ var p = this._get_move(), nms = [];
+ if(p.o && p.o.length) {
+ p.o.children("a").each(function () { nms.push($(this).text().replace(/^\s+/g,"")); });
+ return this._check_unique(nms, p.np.find("> ul > li").not(p.o));
+ }
+ return true;
+ }
+ }
+ });
+})(jQuery);
+//*/ \ No newline at end of file
diff --git a/www/js/jstree-1.0-rc2/jquery.jstree.min.js b/www/js/jstree-1.0-rc2/jquery.jstree.min.js
new file mode 100644
index 0000000..4443655
--- /dev/null
+++ b/www/js/jstree-1.0-rc2/jquery.jstree.min.js
@@ -0,0 +1 @@
+"use strict";(function($){$.vakata={};$.vakata.css={get_css:function(rule_name,delete_flag,sheet){rule_name=rule_name.toLowerCase();var css_rules=sheet.cssRules||sheet.rules,j=0;do{if(css_rules.length&&j>css_rules.length+5){return false}if(css_rules[j].selectorText&&css_rules[j].selectorText.toLowerCase()==rule_name){if(delete_flag===true){if(sheet.removeRule){sheet.removeRule(j)}if(sheet.deleteRule){sheet.deleteRule(j)}return true}else{return css_rules[j]}}}while(css_rules[++j]);return false},add_css:function(rule_name,sheet){if($.jstree.css.get_css(rule_name,false,sheet)){return false}if(sheet.insertRule){sheet.insertRule(rule_name+" { }",0)}else{sheet.addRule(rule_name,null,0)}return $.vakata.css.get_css(rule_name)},remove_css:function(rule_name,sheet){return $.vakata.css.get_css(rule_name,true,sheet)},add_sheet:function(opts){var tmp;if(opts.str){tmp=document.createElement("style");tmp.setAttribute("type","text/css");if(tmp.styleSheet){document.getElementsByTagName("head")[0].appendChild(tmp);tmp.styleSheet.cssText=opts.str}else{tmp.appendChild(document.createTextNode(opts.str));document.getElementsByTagName("head")[0].appendChild(tmp)}return tmp.sheet||tmp.styleSheet}if(opts.url){if(document.createStyleSheet){try{tmp=document.createStyleSheet(opts.url)}catch(e){}}else{tmp=document.createElement("link");tmp.rel="stylesheet";tmp.type="text/css";tmp.media="all";tmp.href=opts.url;document.getElementsByTagName("head")[0].appendChild(tmp);return tmp.styleSheet}}}}})(jQuery);(function($){var instances=[],focused_instance=-1,plugins={},prepared_move={},is_ie6=false;$.fn.jstree=function(settings){var isMethodCall=(typeof settings=="string"),args=Array.prototype.slice.call(arguments,1),returnValue=this;if(!isMethodCall&&$.meta){args.push($.metadata.get(this).jstree)}settings=!isMethodCall&&args.length?$.extend.apply(null,[true,settings].concat(args)):settings;if(isMethodCall&&settings.substring(0,1)=="_"){return returnValue}if(isMethodCall){this.each(function(){var instance=instances[$.data(this,"jstree-instance-id")],methodValue=(instance&&$.isFunction(instance[settings]))?instance[settings].apply(instance,args):instance;if(typeof methodValue!=="undefined"&&(settings.indexOf("is_"===0)||(methodValue!==true&&methodValue!==false))){returnValue=methodValue;return false}})}else{this.each(function(){var instance_id=$.data(this,"jstree-instance-id"),s=false;if(typeof instance_id!=="undefined"&&instances[instance_id]){instances[instance_id].destroy()}instance_id=parseInt(instances.push({}),10)-1;$.data(this,"jstree-instance-id",instance_id);if(!settings){settings={}}settings.plugins=$.isArray(settings.plugins)?settings.plugins:$.jstree.defaults.plugins;if($.inArray("core",settings.plugins)===-1){settings.plugins.unshift("core")}s=$.extend(true,{},$.jstree.defaults,settings);s.plugins=settings.plugins;$.each(plugins,function(i,val){if($.inArray(i,s.plugins)===-1){s[i]=null;delete s[i]}});instances[instance_id]=new $.jstree._instance(instance_id,$(this).addClass("jstree jstree-"+instance_id),s);$.each(instances[instance_id]._get_settings().plugins,function(i,val){instances[instance_id].data[val]={}});$.each(instances[instance_id]._get_settings().plugins,function(i,val){if(plugins[val]){plugins[val].__init.apply(instances[instance_id])}});instances[instance_id].init()})}return returnValue};$.jstree={defaults:{plugins:[]},_focused:function(){return instances[focused_instance]||null},_reference:function(needle){if(instances[needle]){return instances[needle]}var o=$(needle);if(!o.length&&typeof needle==="string"){o=$("#"+needle)}if(!o.length){return null}return instances[o.closest(".jstree").data("jstree-instance-id")]||null},_instance:function(index,container,settings){this.data={core:{}};this.get_settings=function(){return $.extend(true,{},settings)};this._get_settings=function(){return settings};this.get_index=function(){return index};this.get_container=function(){return container};this._set_settings=function(s){settings=$.extend(true,{},settings,s)}},_fn:{},plugin:function(pname,pdata){pdata=$.extend({},{__init:$.noop,__destroy:$.noop,_fn:{},defaults:false},pdata);plugins[pname]=pdata;$.jstree.defaults[pname]=pdata.defaults;$.each(pdata._fn,function(i,val){val.plugin=pname;val.old=$.jstree._fn[i];$.jstree._fn[i]=function(){var rslt,func=val,args=Array.prototype.slice.call(arguments),evnt=new $.Event("before.jstree"),rlbk=false;do{if(func&&func.plugin&&$.inArray(func.plugin,this._get_settings().plugins)!==-1){break}func=func.old}while(func);if(!func){return}rslt=this.get_container().triggerHandler(evnt,{func:i,inst:this,args:args});if(rslt===false){return}if(typeof rslt!=="undefined"){args=rslt}if(i.indexOf("_")===0){rslt=func.apply(this,args)}else{rslt=func.apply($.extend({},this,{__callback:function(data){this.get_container().triggerHandler(i+".jstree",{inst:this,args:args,rslt:data,rlbk:rlbk})},__rollback:function(){rlbk=this.get_rollback();return rlbk},__call_old:function(replace_arguments){return func.old.apply(this,(replace_arguments?Array.prototype.slice.call(arguments,1):args))}}),args)}return rslt};$.jstree._fn[i].old=val.old;$.jstree._fn[i].plugin=pname})},rollback:function(rb){if(rb){if(!$.isArray(rb)){rb=[rb]}$.each(rb,function(i,val){instances[val.i].set_rollback(val.h,val.d)})}}};$.jstree._fn=$.jstree._instance.prototype={};$(function(){var u=navigator.userAgent.toLowerCase(),v=(u.match(/.+?(?:rv|it|ra|ie)[\/: ]([\d.]+)/)||[0,"0"])[1],css_string=".jstree ul, .jstree li { display:block; margin:0 0 0 0; padding:0 0 0 0; list-style-type:none; } .jstree li { display:block; min-height:18px; line-height:18px; white-space:nowrap; margin-left:18px; } .jstree-rtl li { margin-left:0; margin-right:18px; } .jstree > ul > li { margin-left:0px; } .jstree-rtl > ul > li { margin-right:0px; } .jstree ins { display:inline-block; text-decoration:none; width:18px; height:18px; margin:0 0 0 0; padding:0; } .jstree a { display:inline-block; line-height:16px; height:16px; color:black; white-space:nowrap; text-decoration:none; padding:1px 2px; margin:0; } .jstree a:focus { outline: none; } .jstree a > ins { height:16px; width:16px; } .jstree a > .jstree-icon { margin-right:3px; } .jstree-rtl a > .jstree-icon { margin-left:3px; margin-right:0; } li.jstree-open > ul { display:block; } li.jstree-closed > ul { display:none; } ";if(/msie/.test(u)&&parseInt(v,10)==6){is_ie6=true;css_string+=".jstree li { height:18px; margin-left:0; margin-right:0; } .jstree li li { margin-left:18px; } .jstree-rtl li li { margin-left:0px; margin-right:18px; } li.jstree-open ul { display:block; } li.jstree-closed ul { display:none !important; } .jstree li a { display:inline; border-width:0 !important; padding:0px 2px !important; } .jstree li a ins { height:16px; width:16px; margin-right:3px; } .jstree-rtl li a ins { margin-right:0px; margin-left:3px; } "}if(/msie/.test(u)&&parseInt(v,10)==7){css_string+=".jstree li a { border-width:0 !important; padding:0px 2px !important; } "}$.vakata.css.add_sheet({str:css_string})});$.jstree.plugin("core",{__init:function(){this.data.core.to_open=$.map($.makeArray(this.get_settings().core.initially_open),function(n){return"#"+n.toString().replace(/^#/,"").replace("\\/","/").replace("/","\\/")})},defaults:{html_titles:false,animation:500,initially_open:[],rtl:false,strings:{loading:"Loading ...",new_node:"New node"}},_fn:{init:function(){this.set_focus();if(this._get_settings().core.rtl){this.get_container().addClass("jstree-rtl").css("direction","rtl")}this.get_container().html("<ul><li class='jstree-last jstree-leaf'><ins>&#160;</ins><a class='jstree-loading' href='#'><ins class='jstree-icon'>&#160;</ins>"+this._get_settings().core.strings.loading+"</a></li></ul>");this.data.core.li_height=this.get_container().find("ul li.jstree-closed, ul li.jstree-leaf").eq(0).height()||18;this.get_container().delegate("li > ins","click.jstree",$.proxy(function(event){var trgt=$(event.target);if(trgt.is("ins")&&event.pageY-trgt.offset().top<this.data.core.li_height){this.toggle_node(trgt)}},this)).bind("mousedown.jstree",$.proxy(function(){this.set_focus()},this)).bind("dblclick.jstree",function(event){var sel;if(document.selection&&document.selection.empty){document.selection.empty()}else{if(window.getSelection){sel=window.getSelection();try{sel.removeAllRanges();sel.collapse()}catch(err){}}}});this.__callback();this.load_node(-1,function(){this.loaded();this.reopen()})},destroy:function(){var i,n=this.get_index(),s=this._get_settings(),_this=this;$.each(s.plugins,function(i,val){try{plugins[val].__destroy.apply(_this)}catch(err){}});this.__callback();if(this.is_focused()){for(i in instances){if(instances.hasOwnProperty(i)&&i!=n){instances[i].set_focus();break}}}if(n===focused_instance){focused_instance=-1}this.get_container().unbind(".jstree").undelegate(".jstree").removeData("jstree-instance-id").find("[class^='jstree']").andSelf().attr("class",function(){return this.className.replace(/jstree[^ ]*|$/ig,"")});instances[n]=null;delete instances[n]},save_opened:function(){var _this=this;this.data.core.to_open=[];this.get_container().find(".jstree-open").each(function(){_this.data.core.to_open.push("#"+this.id.toString().replace(/^#/,"").replace("\\/","/").replace("/","\\/"))});this.__callback(_this.data.core.to_open)},reopen:function(is_callback){var _this=this,done=true,current=[],remaining=[];if(!is_callback){this.data.core.reopen=false;this.data.core.refreshing=true}if(this.data.core.to_open.length){$.each(this.data.core.to_open,function(i,val){if(val=="#"){return true}if($(val).length&&$(val).is(".jstree-closed")){current.push(val)}else{remaining.push(val)}});if(current.length){this.data.core.to_open=remaining;$.each(current,function(i,val){_this.open_node(val,function(){_this.reopen(true)},true)});done=false}}if(done){if(this.data.core.reopen){clearTimeout(this.data.core.reopen)}this.data.core.reopen=setTimeout(function(){_this.__callback({},_this)},50);this.data.core.refreshing=false}},refresh:function(obj){var _this=this;this.save_opened();if(!obj){obj=-1}obj=this._get_node(obj);if(!obj){obj=-1}if(obj!==-1){obj.children("UL").remove()}this.load_node(obj,function(){_this.__callback({obj:obj});_this.reopen()})},loaded:function(){this.__callback()},set_focus:function(){var f=$.jstree._focused();if(f&&f!==this){f.get_container().removeClass("jstree-focused")}if(f!==this){this.get_container().addClass("jstree-focused");focused_instance=this.get_index()}this.__callback()},is_focused:function(){return focused_instance==this.get_index()},_get_node:function(obj){var $obj=$(obj,this.get_container());if($obj.is(".jstree")||obj==-1){return -1}$obj=$obj.closest("li",this.get_container());return $obj.length?$obj:false},_get_next:function(obj,strict){obj=this._get_node(obj);if(obj===-1){return this.get_container().find("> ul > li:first-child")}if(!obj.length){return false}if(strict){return(obj.nextAll("li").size()>0)?obj.nextAll("li:eq(0)"):false}if(obj.hasClass("jstree-open")){return obj.find("li:eq(0)")}else{if(obj.nextAll("li").size()>0){return obj.nextAll("li:eq(0)")}else{return obj.parentsUntil(".jstree","li").next("li").eq(0)}}},_get_prev:function(obj,strict){obj=this._get_node(obj);if(obj===-1){return this.get_container().find("> ul > li:last-child")}if(!obj.length){return false}if(strict){return(obj.prevAll("li").length>0)?obj.prevAll("li:eq(0)"):false}if(obj.prev("li").length){obj=obj.prev("li").eq(0);while(obj.hasClass("jstree-open")){obj=obj.children("ul:eq(0)").children("li:last")}return obj}else{var o=obj.parentsUntil(".jstree","li:eq(0)");return o.length?o:false}},_get_parent:function(obj){obj=this._get_node(obj);if(obj==-1||!obj.length){return false}var o=obj.parentsUntil(".jstree","li:eq(0)");return o.length?o:-1},_get_children:function(obj){obj=this._get_node(obj);if(obj===-1){return this.get_container().children("ul:eq(0)").children("li")}if(!obj.length){return false}return obj.children("ul:eq(0)").children("li")},get_path:function(obj,id_mode){var p=[],_this=this;obj=this._get_node(obj);if(obj===-1||!obj||!obj.length){return false}obj.parentsUntil(".jstree","li").each(function(){p.push(id_mode?this.id:_this.get_text(this))});p.reverse();p.push(id_mode?obj.attr("id"):this.get_text(obj));return p},is_open:function(obj){obj=this._get_node(obj);return obj&&obj!==-1&&obj.hasClass("jstree-open")},is_closed:function(obj){obj=this._get_node(obj);return obj&&obj!==-1&&obj.hasClass("jstree-closed")},is_leaf:function(obj){obj=this._get_node(obj);return obj&&obj!==-1&&obj.hasClass("jstree-leaf")},open_node:function(obj,callback,skip_animation){obj=this._get_node(obj);if(!obj.length){return false}if(!obj.hasClass("jstree-closed")){if(callback){callback.call()}return false}var s=skip_animation||is_ie6?0:this._get_settings().core.animation,t=this;if(!this._is_loaded(obj)){obj.children("a").addClass("jstree-loading");this.load_node(obj,function(){t.open_node(obj,callback,skip_animation)},callback)}else{if(s){obj.children("ul").css("display","none")}obj.removeClass("jstree-closed").addClass("jstree-open").children("a").removeClass("jstree-loading");if(s){obj.children("ul").stop(true).slideDown(s,function(){this.style.display=""})}this.__callback({obj:obj});if(callback){callback.call()}}},close_node:function(obj,skip_animation){obj=this._get_node(obj);var s=skip_animation||is_ie6?0:this._get_settings().core.animation;if(!obj.length||!obj.hasClass("jstree-open")){return false}if(s){obj.children("ul").attr("style","display:block !important")}obj.removeClass("jstree-open").addClass("jstree-closed");if(s){obj.children("ul").stop(true).slideUp(s,function(){this.style.display=""})}this.__callback({obj:obj})},toggle_node:function(obj){obj=this._get_node(obj);if(obj.hasClass("jstree-closed")){return this.open_node(obj)}if(obj.hasClass("jstree-open")){return this.close_node(obj)}},open_all:function(obj,original_obj){obj=obj?this._get_node(obj):this.get_container();if(!obj||obj===-1){obj=this.get_container()}if(original_obj){obj=obj.find("li.jstree-closed")}else{original_obj=obj;if(obj.is(".jstree-closed")){obj=obj.find("li.jstree-closed").andSelf()}else{obj=obj.find("li.jstree-closed")}}var _this=this;obj.each(function(){var __this=this;if(!_this._is_loaded(this)){_this.open_node(this,function(){_this.open_all(__this,original_obj)},true)}else{_this.open_node(this,false,true)}});if(original_obj.find("li.jstree-closed").length===0){this.__callback({obj:original_obj})}},close_all:function(obj){var _this=this;obj=obj?this._get_node(obj):this.get_container();if(!obj||obj===-1){obj=this.get_container()}obj.find("li.jstree-open").andSelf().each(function(){_this.close_node(this)});this.__callback({obj:obj})},clean_node:function(obj){obj=obj&&obj!=-1?$(obj):this.get_container();obj=obj.is("li")?obj.find("li").andSelf():obj.find("li");obj.removeClass("jstree-last").filter("li:last-child").addClass("jstree-last").end().filter(":has(li)").not(".jstree-open").removeClass("jstree-leaf").addClass("jstree-closed");obj.not(".jstree-open, .jstree-closed").addClass("jstree-leaf").children("ul").remove();this.__callback({obj:obj})},get_rollback:function(){this.__callback();return{i:this.get_index(),h:this.get_container().children("ul").clone(true),d:this.data}},set_rollback:function(html,data){this.get_container().empty().append(html);this.data=data;this.__callback()},load_node:function(obj,s_call,e_call){this.__callback({obj:obj})},_is_loaded:function(obj){return true},create_node:function(obj,position,js,callback,is_loaded){obj=this._get_node(obj);position=typeof position==="undefined"?"last":position;var d=$("<li>"),s=this._get_settings().core,tmp;if(obj!==-1&&!obj.length){return false}if(!is_loaded&&!this._is_loaded(obj)){this.load_node(obj,function(){this.create_node(obj,position,js,callback,true)});return false}this.__rollback();if(typeof js==="string"){js={data:js}}if(!js){js={}}if(js.attr){d.attr(js.attr)}if(js.state){d.addClass("jstree-"+js.state)}if(!js.data){js.data=s.strings.new_node}if(!$.isArray(js.data)){tmp=js.data;js.data=[];js.data.push(tmp)}$.each(js.data,function(i,m){tmp=$("<a>");if($.isFunction(m)){m=m.call(this,js)}if(typeof m=="string"){tmp.attr("href","#")[s.html_titles?"html":"text"](m)}else{if(!m.attr){m.attr={}}if(!m.attr.href){m.attr.href="#"}tmp.attr(m.attr)[s.html_titles?"html":"text"](m.title);if(m.language){tmp.addClass(m.language)}}tmp.prepend("<ins class='jstree-icon'>&#160;</ins>");if(m.icon){if(m.icon.indexOf("/")===-1){tmp.children("ins").addClass(m.icon)}else{tmp.children("ins").css("background","url('"+m.icon+"') center center no-repeat")}}d.append(tmp)});d.prepend("<ins class='jstree-icon'>&#160;</ins>");if(obj===-1){obj=this.get_container();if(position==="before"){position="first"}if(position==="after"){position="last"}}switch(position){case"before":obj.before(d);tmp=this._get_parent(obj);break;case"after":obj.after(d);tmp=this._get_parent(obj);break;case"inside":case"first":if(!obj.children("ul").length){obj.append("<ul>")}obj.children("ul").prepend(d);tmp=obj;break;case"last":if(!obj.children("ul").length){obj.append("<ul>")}obj.children("ul").append(d);tmp=obj;break;default:if(!obj.children("ul").length){obj.append("<ul>")}if(!position){position=0}tmp=obj.children("ul").children("li").eq(position);if(tmp.length){tmp.before(d)}else{obj.children("ul").append(d)}tmp=obj;break}if(tmp===-1||tmp.get(0)===this.get_container().get(0)){tmp=-1}this.clean_node(tmp);this.__callback({obj:d,parent:tmp});if(callback){callback.call(this,d)}return d},get_text:function(obj){obj=this._get_node(obj);if(!obj.length){return false}var s=this._get_settings().core.html_titles;obj=obj.children("a:eq(0)");if(s){obj=obj.clone();obj.children("INS").remove();return obj.html()}else{obj=obj.contents().filter(function(){return this.nodeType==3})[0];return obj.nodeValue}},set_text:function(obj,val){obj=this._get_node(obj);if(!obj.length){return false}obj=obj.children("a:eq(0)");if(this._get_settings().core.html_titles){var tmp=obj.children("INS").clone();obj.html(val).prepend(tmp);this.__callback({obj:obj,name:val});return true}else{obj=obj.contents().filter(function(){return this.nodeType==3})[0];this.__callback({obj:obj,name:val});return(obj.nodeValue=val)}},rename_node:function(obj,val){obj=this._get_node(obj);this.__rollback();if(obj&&obj.length&&this.set_text.apply(this,Array.prototype.slice.call(arguments))){this.__callback({obj:obj,name:val})}},delete_node:function(obj){obj=this._get_node(obj);if(!obj.length){return false}this.__rollback();var p=this._get_parent(obj),prev=this._get_prev(obj);obj=obj.remove();if(p!==-1&&p.find("> ul > li").length===0){p.removeClass("jstree-open jstree-closed").addClass("jstree-leaf")}this.clean_node(p);this.__callback({obj:obj,prev:prev});return obj},prepare_move:function(o,r,pos,cb,is_cb){var p={};p.ot=$.jstree._reference(p.o)||this;p.o=p.ot._get_node(o);p.r=r===-1?-1:this._get_node(r);p.p=(typeof p==="undefined")?"last":pos;if(!is_cb&&prepared_move.o&&prepared_move.o[0]===p.o[0]&&prepared_move.r[0]===p.r[0]&&prepared_move.p===p.p){this.__callback(prepared_move);if(cb){cb.call(this,prepared_move)}return}p.ot=$.jstree._reference(p.o)||this;p.rt=r===-1?p.ot:$.jstree._reference(p.r)||this;if(p.r===-1){p.cr=-1;switch(p.p){case"first":case"before":case"inside":p.cp=0;break;case"after":case"last":p.cp=p.rt.get_container().find(" > ul > li").length;break;default:p.cp=p.p;break}}else{if(!/^(before|after)$/.test(p.p)&&!this._is_loaded(p.r)){return this.load_node(p.r,function(){this.prepare_move(o,r,pos,cb,true)})}switch(p.p){case"before":p.cp=p.r.index();p.cr=p.rt._get_parent(p.r);break;case"after":p.cp=p.r.index()+1;p.cr=p.rt._get_parent(p.r);break;case"inside":case"first":p.cp=0;p.cr=p.r;break;case"last":p.cp=p.r.find(" > ul > li").length;p.cr=p.r;break;default:p.cp=p.p;p.cr=p.r;break}}p.np=p.cr==-1?p.rt.get_container():p.cr;p.op=p.ot._get_parent(p.o);p.or=p.np.find(" > ul > li:nth-child("+(p.cp+1)+")");prepared_move=p;this.__callback(prepared_move);if(cb){cb.call(this,prepared_move)}},check_move:function(){var obj=prepared_move,ret=true;if(obj.or[0]===obj.o[0]){return false}obj.o.each(function(){if(obj.r.parentsUntil(".jstree").andSelf().filter("li").index(this)!==-1){ret=false;return false}});return ret},move_node:function(obj,ref,position,is_copy,is_prepared,skip_check){if(!is_prepared){return this.prepare_move(obj,ref,position,function(p){this.move_node(p,false,false,is_copy,true,skip_check)})}if(!skip_check&&!this.check_move()){return false}this.__rollback();var o=false;if(is_copy){o=obj.o.clone();o.find("*[id]").andSelf().each(function(){if(this.id){this.id="copy_"+this.id}})}else{o=obj.o}if(obj.or.length){obj.or.before(o)}else{if(!obj.np.children("ul").length){$("<ul>").appendTo(obj.np)}obj.np.children("ul:eq(0)").append(o)}try{obj.ot.clean_node(obj.op);obj.rt.clean_node(obj.np);if(!obj.op.find("> ul > li").length){obj.op.removeClass("jstree-open jstree-closed").addClass("jstree-leaf").children("ul").remove()}}catch(e){}if(is_copy){prepared_move.cy=true;prepared_move.oc=o}this.__callback(prepared_move);return prepared_move},_get_move:function(){return prepared_move}}})})(jQuery);(function($){$.jstree.plugin("ui",{__init:function(){this.data.ui.selected=$();this.data.ui.last_selected=false;this.data.ui.hovered=null;this.data.ui.to_select=this.get_settings().ui.initially_select;this.get_container().delegate("a","click.jstree",$.proxy(function(event){event.preventDefault();this.select_node(event.currentTarget,true,event)},this)).delegate("a","mouseenter.jstree",$.proxy(function(event){this.hover_node(event.target)},this)).delegate("a","mouseleave.jstree",$.proxy(function(event){this.dehover_node(event.target)},this)).bind("reopen.jstree",$.proxy(function(){this.reselect()},this)).bind("get_rollback.jstree",$.proxy(function(){this.dehover_node();this.save_selected()},this)).bind("set_rollback.jstree",$.proxy(function(){this.reselect()},this)).bind("close_node.jstree",$.proxy(function(event,data){var s=this._get_settings().ui,obj=this._get_node(data.rslt.obj),clk=(obj&&obj.length)?obj.children("ul").find(".jstree-clicked"):$(),_this=this;if(s.selected_parent_close===false||!clk.length){return}clk.each(function(){_this.deselect_node(this);if(s.selected_parent_close==="select_parent"){_this.select_node(obj)}})},this)).bind("delete_node.jstree",$.proxy(function(event,data){var s=this._get_settings().ui.select_prev_on_delete,obj=this._get_node(data.rslt.obj),clk=(obj&&obj.length)?obj.find(".jstree-clicked"):[],_this=this;clk.each(function(){_this.deselect_node(this)});if(s&&clk.length){this.select_node(data.rslt.prev)}},this)).bind("move_node.jstree",$.proxy(function(event,data){if(data.rslt.cy){data.rslt.oc.find(".jstree-clicked").removeClass("jstree-clicked")}},this))},defaults:{select_limit:-1,select_multiple_modifier:"ctrl",selected_parent_close:"select_parent",select_prev_on_delete:true,disable_selecting_children:false,initially_select:[]},_fn:{_get_node:function(obj,allow_multiple){if(typeof obj==="undefined"||obj===null){return allow_multiple?this.data.ui.selected:this.data.ui.last_selected}var $obj=$(obj,this.get_container());if($obj.is(".jstree")||obj==-1){return -1}$obj=$obj.closest("li",this.get_container());return $obj.length?$obj:false},save_selected:function(){var _this=this;this.data.ui.to_select=[];this.data.ui.selected.each(function(){_this.data.ui.to_select.push("#"+this.id.toString().replace(/^#/,"").replace("\\/","/").replace("/","\\/"))});this.__callback(this.data.ui.to_select)},reselect:function(){var _this=this,s=this.data.ui.to_select;s=$.map($.makeArray(s),function(n){return"#"+n.toString().replace(/^#/,"").replace("\\/","/").replace("/","\\/")});this.deselect_all();$.each(s,function(i,val){if(val&&val!=="#"){_this.select_node(val)}});this.__callback()},refresh:function(obj){this.save_selected();return this.__call_old()},hover_node:function(obj){obj=this._get_node(obj);if(!obj.length){return false}if(!obj.hasClass("jstree-hovered")){this.dehover_node()}this.data.ui.hovered=obj.children("a").addClass("jstree-hovered").parent();this.__callback({obj:obj})},dehover_node:function(){var obj=this.data.ui.hovered,p;if(!obj||!obj.length){return false}p=obj.children("a").removeClass("jstree-hovered").parent();if(this.data.ui.hovered[0]===p[0]){this.data.ui.hovered=null}this.__callback({obj:obj})},select_node:function(obj,check,e){obj=this._get_node(obj);if(obj==-1||!obj||!obj.length){return false}var s=this._get_settings().ui,is_multiple=(s.select_multiple_modifier=="on"||(s.select_multiple_modifier!==false&&e&&e[s.select_multiple_modifier+"Key"])),is_selected=this.is_selected(obj),proceed=true;if(check){if(s.disable_selecting_children&&is_multiple&&obj.parents("li",this.get_container()).children(".jstree-clicked").length){return false}proceed=false;switch(!0){case (is_selected&&!is_multiple):this.deselect_all();is_selected=false;proceed=true;break;case (!is_selected&&!is_multiple):if(s.select_limit==-1||s.select_limit>0){this.deselect_all();proceed=true}break;case (is_selected&&is_multiple):this.deselect_node(obj);break;case (!is_selected&&is_multiple):if(s.select_limit==-1||this.data.ui.selected.length+1<=s.select_limit){proceed=true}break}}if(proceed&&!is_selected){obj.children("a").addClass("jstree-clicked");this.data.ui.selected=this.data.ui.selected.add(obj);this.data.ui.last_selected=obj;this.__callback({obj:obj})}},deselect_node:function(obj){obj=this._get_node(obj);if(!obj.length){return false}if(this.is_selected(obj)){obj.children("a").removeClass("jstree-clicked");this.data.ui.selected=this.data.ui.selected.not(obj);if(this.data.ui.last_selected.get(0)===obj.get(0)){this.data.ui.last_selected=this.data.ui.selected.eq(0)}this.__callback({obj:obj})}},toggle_select:function(obj){obj=this._get_node(obj);if(!obj.length){return false}if(this.is_selected(obj)){this.deselect_node(obj)}else{this.select_node(obj)}},is_selected:function(obj){return this.data.ui.selected.index(this._get_node(obj))>=0},get_selected:function(context){return context?$(context).find(".jstree-clicked").parent():this.data.ui.selected},deselect_all:function(context){if(context){$(context).find(".jstree-clicked").removeClass("jstree-clicked")}else{this.get_container().find(".jstree-clicked").removeClass("jstree-clicked")}this.data.ui.selected=$([]);this.data.ui.last_selected=false;this.__callback()}}});$.jstree.defaults.plugins.push("ui")})(jQuery);(function($){$.jstree.plugin("crrm",{__init:function(){this.get_container().bind("move_node.jstree",$.proxy(function(e,data){if(this._get_settings().crrm.move.open_onmove){var t=this;data.rslt.np.parentsUntil(".jstree").andSelf().filter(".jstree-closed").each(function(){t.open_node(this,false,true)})}},this))},defaults:{input_width_limit:200,move:{always_copy:false,open_onmove:true,default_position:"last",check_move:function(m){return true}}},_fn:{_show_input:function(obj,callback){obj=this._get_node(obj);var rtl=this._get_settings().core.rtl,w=this._get_settings().crrm.input_width_limit,w1=obj.children("ins").width(),w2=obj.find("> a:visible > ins").width()*obj.find("> a:visible > ins").length,t=this.get_text(obj),h1=$("<div>",{css:{position:"absolute",top:"-200px",left:(rtl?"0px":"-1000px"),visibility:"hidden"}}).appendTo("body"),h2=obj.css("position","relative").append($("<input>",{value:t,css:{padding:"0",border:"1px solid silver",position:"absolute",left:(rtl?"auto":(w1+w2+4)+"px"),right:(rtl?(w1+w2+4)+"px":"auto"),top:"0px",height:(this.data.core.li_height-2)+"px",lineHeight:(this.data.core.li_height-2)+"px",width:"150px"},blur:$.proxy(function(){var i=obj.children("input"),v=i.val();if(v===""){v=t}i.remove();this.set_text(obj,t);this.rename_node(obj,v);callback.call(this,obj,v,t);obj.css("position","")},this),keyup:function(event){var key=event.keyCode||event.which;if(key==27){this.value=t;this.blur();return}else{if(key==13){this.blur();return}else{h2.width(Math.min(h1.text("pW"+this.value).width(),w))}}}})).children("input");this.set_text(obj,"");h1.css({fontFamily:h2.css("fontFamily")||"",fontSize:h2.css("fontSize")||"",fontWeight:h2.css("fontWeight")||"",fontStyle:h2.css("fontStyle")||"",fontStretch:h2.css("fontStretch")||"",fontVariant:h2.css("fontVariant")||"",letterSpacing:h2.css("letterSpacing")||"",wordSpacing:h2.css("wordSpacing")||""});h2.width(Math.min(h1.text("pW"+h2[0].value).width(),w))[0].select()},rename:function(obj){obj=this._get_node(obj);this.__rollback();var f=this.__callback;this._show_input(obj,function(obj,new_name,old_name){f.call(this,{obj:obj,new_name:new_name,old_name:old_name})})},create:function(obj,position,js,callback,skip_rename){var t,_this=this;obj=this._get_node(obj);if(!obj){obj=-1}this.__rollback();t=this.create_node(obj,position,js,function(t){var p=this._get_parent(t),pos=$(t).index();if(callback){callback.call(this,t)}if(p.length&&p.hasClass("jstree-closed")){this.open_node(p,false,true)}if(!skip_rename){this._show_input(t,function(obj,new_name,old_name){_this.__callback({obj:obj,name:new_name,parent:p,position:pos})})}else{_this.__callback({obj:t,name:this.get_text(t),parent:p,position:pos})}});return t},remove:function(obj){obj=this._get_node(obj,true);this.__rollback();this.delete_node(obj);this.__callback({obj:obj})},check_move:function(){if(!this.__call_old()){return false}var s=this._get_settings().crrm.move;if(!s.check_move.call(this,this._get_move())){return false}return true},move_node:function(obj,ref,position,is_copy,is_prepared,skip_check){var s=this._get_settings().crrm.move;if(!is_prepared){if(!position){position=s.default_position}if(position==="inside"&&!s.default_position.match(/^(before|after)$/)){position=s.default_position}return this.__call_old(true,obj,ref,position,is_copy,false,skip_check)}if(s.always_copy===true||(s.always_copy==="multitree"&&obj.rt.get_index()!==obj.ot.get_index())){is_copy=true}this.__call_old(true,obj,ref,position,is_copy,true,skip_check)},cut:function(obj){obj=this._get_node(obj);this.data.crrm.cp_nodes=false;this.data.crrm.ct_nodes=false;if(!obj||!obj.length){return false}this.data.crrm.ct_nodes=obj},copy:function(obj){obj=this._get_node(obj);this.data.crrm.cp_nodes=false;this.data.crrm.ct_nodes=false;if(!obj||!obj.length){return false}this.data.crrm.cp_nodes=obj},paste:function(obj){obj=this._get_node(obj);if(!obj||!obj.length){return false}if(!this.data.crrm.ct_nodes&&!this.data.crrm.cp_nodes){return false}if(this.data.crrm.ct_nodes){this.move_node(this.data.crrm.ct_nodes,obj)}if(this.data.crrm.cp_nodes){this.move_node(this.data.crrm.cp_nodes,obj,false,true)}this.data.crrm.cp_nodes=false;this.data.crrm.ct_nodes=false}}});$.jstree.defaults.plugins.push("crrm")})(jQuery);(function($){var themes_loaded=[];$.jstree._themes=false;$.jstree.plugin("themes",{__init:function(){this.get_container().bind("init.jstree",$.proxy(function(){var s=this._get_settings().themes;this.data.themes.dots=s.dots;this.data.themes.icons=s.icons;this.set_theme(s.theme,s.url)},this)).bind("loaded.jstree",$.proxy(function(){if(!this.data.themes.dots){this.hide_dots()}else{this.show_dots()}if(!this.data.themes.icons){this.hide_icons()}else{this.show_icons()}},this))},defaults:{theme:"default",url:false,dots:true,icons:true},_fn:{set_theme:function(theme_name,theme_url){if(!theme_name){return false}if(!theme_url){theme_url=$.jstree._themes+theme_name+"/style.css"}if($.inArray(theme_url,themes_loaded)==-1){$.vakata.css.add_sheet({url:theme_url,rel:"jstree"});themes_loaded.push(theme_url)}if(this.data.themes.theme!=theme_name){this.get_container().removeClass("jstree-"+this.data.themes.theme);this.data.themes.theme=theme_name}this.get_container().addClass("jstree-"+theme_name);if(!this.data.themes.dots){this.hide_dots()}else{this.show_dots()}if(!this.data.themes.icons){this.hide_icons()}else{this.show_icons()}this.__callback()},get_theme:function(){return this.data.themes.theme},show_dots:function(){this.data.themes.dots=true;this.get_container().children("ul").removeClass("jstree-no-dots")},hide_dots:function(){this.data.themes.dots=false;this.get_container().children("ul").addClass("jstree-no-dots")},toggle_dots:function(){if(this.data.themes.dots){this.hide_dots()}else{this.show_dots()}},show_icons:function(){this.data.themes.icons=true;this.get_container().children("ul").removeClass("jstree-no-icons")},hide_icons:function(){this.data.themes.icons=false;this.get_container().children("ul").addClass("jstree-no-icons")},toggle_icons:function(){if(this.data.themes.icons){this.hide_icons()}else{this.show_icons()}}}});$(function(){if($.jstree._themes===false){$("script").each(function(){if(this.src.toString().match(/jquery\.jstree[^\/]*?\.js(\?.*)?$/)){$.jstree._themes=this.src.toString().replace(/jquery\.jstree[^\/]*?\.js(\?.*)?$/,"")+"themes/";return false}})}if($.jstree._themes===false){$.jstree._themes="themes/"}});$.jstree.defaults.plugins.push("themes")})(jQuery);(function($){var bound=[];function exec(i,event){var f=$.jstree._focused(),tmp;if(f&&f.data&&f.data.hotkeys&&f.data.hotkeys.enabled){tmp=f._get_settings().hotkeys[i];if(tmp){return tmp.call(f,event)}}}$.jstree.plugin("hotkeys",{__init:function(){if(typeof $.hotkeys==="undefined"){throw"jsTree hotkeys: jQuery hotkeys plugin not included."}if(!this.data.ui){throw"jsTree hotkeys: jsTree UI plugin not included."}$.each(this._get_settings().hotkeys,function(i,val){if($.inArray(i,bound)==-1){$(document).bind("keydown",i,function(event){return exec(i,event)});bound.push(i)}});this.enable_hotkeys()},defaults:{up:function(){var o=this.data.ui.hovered||this.data.ui.last_selected||-1;this.hover_node(this._get_prev(o));return false},down:function(){var o=this.data.ui.hovered||this.data.ui.last_selected||-1;this.hover_node(this._get_next(o));return false},left:function(){var o=this.data.ui.hovered||this.data.ui.last_selected;if(o){if(o.hasClass("jstree-open")){this.close_node(o)}else{this.hover_node(this._get_prev(o))}}return false},right:function(){var o=this.data.ui.hovered||this.data.ui.last_selected;if(o&&o.length){if(o.hasClass("jstree-closed")){this.open_node(o)}else{this.hover_node(this._get_next(o))}}return false},space:function(){if(this.data.ui.hovered){this.data.ui.hovered.children("a:eq(0)").click()}return false},"ctrl+space":function(event){event.type="click";if(this.data.ui.hovered){this.data.ui.hovered.children("a:eq(0)").trigger(event)}return false},f2:function(){this.rename(this.data.ui.hovered||this.data.ui.last_selected)},del:function(){this.remove(this.data.ui.hovered||this._get_node(null))}},_fn:{enable_hotkeys:function(){this.data.hotkeys.enabled=true},disable_hotkeys:function(){this.data.hotkeys.enabled=false}}})})(jQuery);(function($){$.jstree.plugin("json_data",{defaults:{data:false,ajax:false,correct_state:true,progressive_render:false},_fn:{load_node:function(obj,s_call,e_call){var _this=this;this.load_node_json(obj,function(){_this.__callback({obj:obj});s_call.call(this)},e_call)},_is_loaded:function(obj){var s=this._get_settings().json_data,d;obj=this._get_node(obj);if(obj&&obj!==-1&&s.progressive_render&&!obj.is(".jstree-open, .jstree-leaf")&&obj.children("ul").children("li").length===0&&obj.data("jstree-children")){d=this._parse_json(obj.data("jstree-children"));if(d){obj.append(d);$.removeData(obj,"jstree-children")}this.clean_node(obj);return true}return obj==-1||!obj||!s.ajax||obj.is(".jstree-open, .jstree-leaf")||obj.children("ul").children("li").size()>0},load_node_json:function(obj,s_call,e_call){var s=this.get_settings().json_data,d,error_func=function(){},success_func=function(){};obj=this._get_node(obj);if(obj&&obj!==-1){if(obj.data("jstree-is-loading")){return}else{obj.data("jstree-is-loading",true)}}switch(!0){case (!s.data&&!s.ajax):throw"Neither data nor ajax settings supplied.";case (!!s.data&&!s.ajax)||(!!s.data&&!!s.ajax&&(!obj||obj===-1)):if(!obj||obj==-1){d=this._parse_json(s.data);if(d){this.get_container().children("ul").empty().append(d.children());this.clean_node()}else{if(s.correct_state){this.get_container().children("ul").empty()}}}if(s_call){s_call.call(this)}break;case (!s.data&&!!s.ajax)||(!!s.data&&!!s.ajax&&obj&&obj!==-1):error_func=function(x,t,e){var ef=this.get_settings().json_data.ajax.error;if(ef){ef.call(this,x,t,e)}if(obj!=-1&&obj.length){obj.children(".jstree-loading").removeClass("jstree-loading");obj.data("jstree-is-loading",false);if(t==="success"&&s.correct_state){obj.removeClass("jstree-open jstree-closed").addClass("jstree-leaf")}}else{if(t==="success"&&s.correct_state){this.get_container().children("ul").empty()}}if(e_call){e_call.call(this)}};success_func=function(d,t,x){var sf=this.get_settings().json_data.ajax.success;if(sf){d=sf.call(this,d,t,x)||d}if(d===""||(!$.isArray(d)&&!$.isPlainObject(d))){return error_func.call(this,x,t,"")}d=this._parse_json(d);if(d){if(obj===-1||!obj){this.get_container().children("ul").empty().append(d.children())}else{obj.append(d).children(".jstree-loading").removeClass("jstree-loading");obj.data("jstree-is-loading",false)}this.clean_node(obj);if(s_call){s_call.call(this)}}else{if(obj===-1||!obj){if(s.correct_state){this.get_container().children("ul").empty();if(s_call){s_call.call(this)}}}else{obj.children(".jstree-loading").removeClass("jstree-loading");obj.data("jstree-is-loading",false);if(s.correct_state){obj.removeClass("jstree-open jstree-closed").addClass("jstree-leaf");if(s_call){s_call.call(this)}}}}};s.ajax.context=this;s.ajax.error=error_func;s.ajax.success=success_func;if(!s.ajax.dataType){s.ajax.dataType="json"}if($.isFunction(s.ajax.url)){s.ajax.url=s.ajax.url.call(this,obj)}if($.isFunction(s.ajax.data)){s.ajax.data=s.ajax.data.call(this,obj)}$.ajax(s.ajax);break}},_parse_json:function(js,is_callback){var d=false,p=this._get_settings(),s=p.json_data,t=p.core.html_titles,tmp,i,j,ul1,ul2;if(!js){return d}if($.isFunction(js)){js=js.call(this)}if($.isArray(js)){d=$();if(!js.length){return false}for(i=0,j=js.length;i<j;i++){tmp=this._parse_json(js[i],true);if(tmp.length){d=d.add(tmp)}}}else{if(typeof js=="string"){js={data:js}}if(!js.data&&js.data!==""){return d}d=$("<li>");if(js.attr){d.attr(js.attr)}if(js.metadata){d.data("jstree",js.metadata)}if(js.state){d.addClass("jstree-"+js.state)}if(!$.isArray(js.data)){tmp=js.data;js.data=[];js.data.push(tmp)}$.each(js.data,function(i,m){tmp=$("<a>");if($.isFunction(m)){m=m.call(this,js)}if(typeof m=="string"){tmp.attr("href","#")[t?"html":"text"](m)}else{if(!m.attr){m.attr={}}if(!m.attr.href){m.attr.href="#"}tmp.attr(m.attr)[t?"html":"text"](m.title);if(m.language){tmp.addClass(m.language)}}tmp.prepend("<ins class='jstree-icon'>&#160;</ins>");if(!m.icon&&js.icon){m.icon=js.icon}if(m.icon){if(m.icon.indexOf("/")===-1){tmp.children("ins").addClass(m.icon)}else{tmp.children("ins").css("background","url('"+m.icon+"') center center no-repeat")}}d.append(tmp)});d.prepend("<ins class='jstree-icon'>&#160;</ins>");if(js.children){if(s.progressive_render&&js.state!=="open"){d.addClass("jstree-closed").data("jstree-children",js.children)}else{if($.isFunction(js.children)){js.children=js.children.call(this,js)}if($.isArray(js.children)&&js.children.length){tmp=this._parse_json(js.children,true);if(tmp.length){ul2=$("<ul>");ul2.append(tmp);d.append(ul2)}}}}}if(!is_callback){ul1=$("<ul>");ul1.append(d);d=ul1}return d},get_json:function(obj,li_attr,a_attr,is_callback){var result=[],s=this._get_settings(),_this=this,tmp1,tmp2,li,a,t,lang;obj=this._get_node(obj);if(!obj||obj===-1){obj=this.get_container().find("> ul > li")}li_attr=$.isArray(li_attr)?li_attr:["id","class"];if(!is_callback&&this.data.types){li_attr.push(s.types.type_attr)}a_attr=$.isArray(a_attr)?a_attr:[];obj.each(function(){li=$(this);tmp1={data:[]};if(li_attr.length){tmp1.attr={}}$.each(li_attr,function(i,v){tmp2=li.attr(v);if(tmp2&&tmp2.length&&tmp2.replace(/jstree[^ ]*|$/ig,"").length){tmp1.attr[v]=tmp2.replace(/jstree[^ ]*|$/ig,"")}});if(li.hasClass("jstree-open")){tmp1.state="open"}if(li.hasClass("jstree-closed")){tmp1.state="closed"}a=li.children("a");a.each(function(){t=$(this);if(a_attr.length||$.inArray("languages",s.plugins)!==-1||t.children("ins").get(0).style.backgroundImage.length||(t.children("ins").get(0).className&&t.children("ins").get(0).className.replace(/jstree[^ ]*|$/ig,"").length)){lang=false;if($.inArray("languages",s.plugins)!==-1&&$.isArray(s.languages)&&s.languages.length){$.each(s.languages,function(l,lv){if(t.hasClass(lv)){lang=lv;return false}})}tmp2={attr:{},title:_this.get_text(t,lang)};$.each(a_attr,function(k,z){tmp1.attr[z]=(t.attr(z)||"").replace(/jstree[^ ]*|$/ig,"")});$.each(s.languages,function(k,z){if(t.hasClass(z)){tmp2.language=z;return true}});if(t.children("ins").get(0).className.replace(/jstree[^ ]*|$/ig,"").replace(/^\s+$/ig,"").length){tmp2.icon=t.children("ins").get(0).className.replace(/jstree[^ ]*|$/ig,"").replace(/^\s+$/ig,"")}if(t.children("ins").get(0).style.backgroundImage.length){tmp2.icon=t.children("ins").get(0).style.backgroundImage.replace("url(","").replace(")","")}}else{tmp2=_this.get_text(t)}if(a.length>1){tmp1.data.push(tmp2)}else{tmp1.data=tmp2}});li=li.find("> ul > li");if(li.length){tmp1.children=_this.get_json(li,li_attr,a_attr,true)}result.push(tmp1)});return result}}})})(jQuery);(function($){$.jstree.plugin("languages",{__init:function(){this._load_css()},defaults:[],_fn:{set_lang:function(i){var langs=this._get_settings().languages,st=false,selector=".jstree-"+this.get_index()+" a";if(!$.isArray(langs)||langs.length===0){return false}if($.inArray(i,langs)==-1){if(!!langs[i]){i=langs[i]}else{return false}}if(i==this.data.languages.current_language){return true}st=$.vakata.css.get_css(selector+"."+this.data.languages.current_language,false,this.data.languages.language_css);if(st!==false){st.style.display="none"}st=$.vakata.css.get_css(selector+"."+i,false,this.data.languages.language_css);if(st!==false){st.style.display=""}this.data.languages.current_language=i;this.__callback(i);return true},get_lang:function(){return this.data.languages.current_language},get_text:function(obj,lang){obj=this._get_node(obj)||this.data.ui.last_selected;if(!obj.size()){return false}var langs=this._get_settings().languages,s=this._get_settings().core.html_titles;if($.isArray(langs)&&langs.length){lang=(lang&&$.inArray(lang,langs)!=-1)?lang:this.data.languages.current_language;obj=obj.children("a."+lang)}else{obj=obj.children("a:eq(0)")}if(s){obj=obj.clone();obj.children("INS").remove();return obj.html()}else{obj=obj.contents().filter(function(){return this.nodeType==3})[0];return obj.nodeValue}},set_text:function(obj,val,lang){obj=this._get_node(obj)||this.data.ui.last_selected;if(!obj.size()){return false}var langs=this._get_settings().languages,s=this._get_settings().core.html_titles,tmp;if($.isArray(langs)&&langs.length){lang=(lang&&$.inArray(lang,langs)!=-1)?lang:this.data.languages.current_language;obj=obj.children("a."+lang)}else{obj=obj.children("a:eq(0)")}if(s){tmp=obj.children("INS").clone();obj.html(val).prepend(tmp);this.__callback({obj:obj,name:val,lang:lang});return true}else{obj=obj.contents().filter(function(){return this.nodeType==3})[0];this.__callback({obj:obj,name:val,lang:lang});return(obj.nodeValue=val)}},_load_css:function(){var langs=this._get_settings().languages,str="/* languages css */",selector=".jstree-"+this.get_index()+" a",ln;if($.isArray(langs)&&langs.length){this.data.languages.current_language=langs[0];for(ln=0;ln<langs.length;ln++){str+=selector+"."+langs[ln]+" {";if(langs[ln]!=this.data.languages.current_language){str+=" display:none; "}str+=" } "}this.data.languages.language_css=$.vakata.css.add_sheet({str:str})}},create_node:function(obj,position,js,callback){var t=this.__call_old(true,obj,position,js,function(t){var langs=this._get_settings().languages,a=t.children("a"),ln;if($.isArray(langs)&&langs.length){for(ln=0;ln<langs.length;ln++){if(!a.is("."+langs[ln])){t.append(a.eq(0).clone().removeClass(langs.join(" ")).addClass(langs[ln]))}}a.not("."+langs.join(", .")).remove()}if(callback){callback.call(this,t)}});return t}}})})(jQuery);(function($){$.jstree.plugin("cookies",{__init:function(){if(typeof $.cookie==="undefined"){throw"jsTree cookie: jQuery cookie plugin not included."}var s=this._get_settings().cookies,tmp;if(!!s.save_opened){tmp=$.cookie(s.save_opened);if(tmp&&tmp.length){this.data.core.to_open=tmp.split(",")}}if(!!s.save_selected){tmp=$.cookie(s.save_selected);if(tmp&&tmp.length&&this.data.ui){this.data.ui.to_select=tmp.split(",")}}this.get_container().one((this.data.ui?"reselect":"reopen")+".jstree",$.proxy(function(){this.get_container().bind("open_node.jstree close_node.jstree select_node.jstree deselect_node.jstree",$.proxy(function(e){if(this._get_settings().cookies.auto_save){this.save_cookie((e.handleObj.namespace+e.handleObj.type).replace("jstree",""))}},this))},this))},defaults:{save_opened:"jstree_open",save_selected:"jstree_select",auto_save:true,cookie_options:{}},_fn:{save_cookie:function(c){if(this.data.core.refreshing){return}var s=this._get_settings().cookies;if(!c){if(s.save_opened){this.save_opened();$.cookie(s.save_opened,this.data.core.to_open.join(","),s.cookie_options)}if(s.save_selected&&this.data.ui){this.save_selected();$.cookie(s.save_selected,this.data.ui.to_select.join(","),s.cookie_options)}return}switch(c){case"open_node":case"close_node":if(!!s.save_opened){this.save_opened();$.cookie(s.save_opened,this.data.core.to_open.join(","),s.cookie_options)}break;case"select_node":case"deselect_node":if(!!s.save_selected&&this.data.ui){this.save_selected();$.cookie(s.save_selected,this.data.ui.to_select.join(","),s.cookie_options)}break}}}});$.jstree.defaults.plugins.push("cookies")})(jQuery);(function($){$.jstree.plugin("sort",{__init:function(){this.get_container().bind("load_node.jstree",$.proxy(function(e,data){var obj=this._get_node(data.rslt.obj);obj=obj===-1?this.get_container().children("ul"):obj.children("ul");this.sort(obj)},this)).bind("rename_node.jstree",$.proxy(function(e,data){this.sort(data.rslt.obj.parent())},this)).bind("move_node.jstree",$.proxy(function(e,data){var m=data.rslt.np==-1?this.get_container():data.rslt.np;this.sort(m.children("ul"))},this))},defaults:function(a,b){return this.get_text(a)>this.get_text(b)?1:-1},_fn:{sort:function(obj){var s=this._get_settings().sort,t=this;obj.append($.makeArray(obj.children("li")).sort($.proxy(s,t)));obj.find("> li > ul").each(function(){t.sort($(this))});this.clean_node(obj)}}})})(jQuery);(function($){var o=false,r=false,m=false,sli=false,sti=false,dir1=false,dir2=false;$.vakata.dnd={is_down:false,is_drag:false,helper:false,scroll_spd:10,init_x:0,init_y:0,threshold:5,user_data:{},drag_start:function(e,data,html){if($.vakata.dnd.is_drag){$.vakata.drag_stop({})}try{e.currentTarget.unselectable="on";e.currentTarget.onselectstart=function(){return false};if(e.currentTarget.style){e.currentTarget.style.MozUserSelect="none"}}catch(err){}$.vakata.dnd.init_x=e.pageX;$.vakata.dnd.init_y=e.pageY;$.vakata.dnd.user_data=data;$.vakata.dnd.is_down=true;$.vakata.dnd.helper=$("<div id='vakata-dragged'>").html(html).css("opacity","0.75");$(document).bind("mousemove",$.vakata.dnd.drag);$(document).bind("mouseup",$.vakata.dnd.drag_stop);return false},drag:function(e){if(!$.vakata.dnd.is_down){return}if(!$.vakata.dnd.is_drag){if(Math.abs(e.pageX-$.vakata.dnd.init_x)>5||Math.abs(e.pageY-$.vakata.dnd.init_y)>5){$.vakata.dnd.helper.appendTo("body");$.vakata.dnd.is_drag=true;$(document).triggerHandler("drag_start.vakata",{event:e,data:$.vakata.dnd.user_data})}else{return}}if(e.type==="mousemove"){var d=$(document),t=d.scrollTop(),l=d.scrollLeft();if(e.pageY-t<20){if(sti&&dir1==="down"){clearInterval(sti);sti=false}if(!sti){dir1="up";sti=setInterval(function(){$(document).scrollTop($(document).scrollTop()-$.vakata.dnd.scroll_spd)},150)}}else{if(sti&&dir1==="up"){clearInterval(sti);sti=false}}if($(window).height()-(e.pageY-t)<20){if(sti&&dir1==="up"){clearInterval(sti);sti=false}if(!sti){dir1="down";sti=setInterval(function(){$(document).scrollTop($(document).scrollTop()+$.vakata.dnd.scroll_spd)},150)}}else{if(sti&&dir1==="down"){clearInterval(sti);sti=false}}if(e.pageX-l<20){if(sli&&dir2==="right"){clearInterval(sli);sli=false}if(!sli){dir2="left";sli=setInterval(function(){$(document).scrollLeft($(document).scrollLeft()-$.vakata.dnd.scroll_spd)},150)}}else{if(sli&&dir2==="left"){clearInterval(sli);sli=false}}if($(window).width()-(e.pageX-l)<20){if(sli&&dir2==="left"){clearInterval(sli);sli=false}if(!sli){dir2="right";sli=setInterval(function(){$(document).scrollLeft($(document).scrollLeft()+$.vakata.dnd.scroll_spd)},150)}}else{if(sli&&dir2==="right"){clearInterval(sli);sli=false}}}$.vakata.dnd.helper.css({left:(e.pageX+5)+"px",top:(e.pageY+10)+"px"});$(document).triggerHandler("drag.vakata",{event:e,data:$.vakata.dnd.user_data})},drag_stop:function(e){$(document).unbind("mousemove",$.vakata.dnd.drag);$(document).unbind("mouseup",$.vakata.dnd.drag_stop);$(document).triggerHandler("drag_stop.vakata",{event:e,data:$.vakata.dnd.user_data});$.vakata.dnd.helper.remove();$.vakata.dnd.init_x=0;$.vakata.dnd.init_y=0;$.vakata.dnd.user_data={};$.vakata.dnd.is_down=false;$.vakata.dnd.is_drag=false}};$(function(){var css_string="#vakata-dragged { display:block; margin:0 0 0 0; padding:4px 4px 4px 24px; position:absolute; top:-2000px; line-height:16px; z-index:10000; } ";$.vakata.css.add_sheet({str:css_string})});$.jstree.plugin("dnd",{__init:function(){this.data.dnd={active:false,after:false,inside:false,before:false,off:false,prepared:false,w:0,to1:false,to2:false,cof:false,cw:false,ch:false,i1:false,i2:false};this.get_container().bind("mouseenter.jstree",$.proxy(function(){if($.vakata.dnd.is_drag&&$.vakata.dnd.user_data.jstree&&this.data.themes){m.attr("class","jstree-"+this.data.themes.theme);$.vakata.dnd.helper.attr("class","jstree-dnd-helper jstree-"+this.data.themes.theme)}},this)).bind("mouseleave.jstree",$.proxy(function(){if($.vakata.dnd.is_drag&&$.vakata.dnd.user_data.jstree){if(this.data.dnd.i1){clearInterval(this.data.dnd.i1)}if(this.data.dnd.i2){clearInterval(this.data.dnd.i2)}}},this)).bind("mousemove.jstree",$.proxy(function(e){if($.vakata.dnd.is_drag&&$.vakata.dnd.user_data.jstree){var cnt=this.get_container()[0];if(e.pageX+24>this.data.dnd.cof.left+this.data.dnd.cw){if(this.data.dnd.i1){clearInterval(this.data.dnd.i1)}this.data.dnd.i1=setInterval($.proxy(function(){this.scrollLeft+=$.vakata.dnd.scroll_spd},cnt),100)}else{if(e.pageX-24<this.data.dnd.cof.left){if(this.data.dnd.i1){clearInterval(this.data.dnd.i1)}this.data.dnd.i1=setInterval($.proxy(function(){this.scrollLeft-=$.vakata.dnd.scroll_spd},cnt),100)}else{if(this.data.dnd.i1){clearInterval(this.data.dnd.i1)}}}if(e.pageY+24>this.data.dnd.cof.top+this.data.dnd.ch){if(this.data.dnd.i2){clearInterval(this.data.dnd.i2)}this.data.dnd.i2=setInterval($.proxy(function(){this.scrollTop+=$.vakata.dnd.scroll_spd},cnt),100)}else{if(e.pageY-24<this.data.dnd.cof.top){if(this.data.dnd.i2){clearInterval(this.data.dnd.i2)}this.data.dnd.i2=setInterval($.proxy(function(){this.scrollTop-=$.vakata.dnd.scroll_spd},cnt),100)}else{if(this.data.dnd.i2){clearInterval(this.data.dnd.i2)}}}}},this)).delegate("a","mousedown.jstree",$.proxy(function(e){if(e.which===1){this.start_drag(e.currentTarget,e);return false}},this)).delegate("a","mouseenter.jstree",$.proxy(function(e){if($.vakata.dnd.is_drag&&$.vakata.dnd.user_data.jstree){this.dnd_enter(e.currentTarget)}},this)).delegate("a","mousemove.jstree",$.proxy(function(e){if($.vakata.dnd.is_drag&&$.vakata.dnd.user_data.jstree){if(typeof this.data.dnd.off.top==="undefined"){this.data.dnd.off=$(e.target).offset()}this.data.dnd.w=(e.pageY-(this.data.dnd.off.top||0))%this.data.core.li_height;if(this.data.dnd.w<0){this.data.dnd.w+=this.data.core.li_height}this.dnd_show()}},this)).delegate("a","mouseleave.jstree",$.proxy(function(e){if($.vakata.dnd.is_drag&&$.vakata.dnd.user_data.jstree){this.data.dnd.after=false;this.data.dnd.before=false;this.data.dnd.inside=false;$.vakata.dnd.helper.children("ins").attr("class","jstree-invalid");m.hide();if(r&&r[0]===e.target.parentNode){if(this.data.dnd.to1){clearTimeout(this.data.dnd.to1);this.data.dnd.to1=false}if(this.data.dnd.to2){clearTimeout(this.data.dnd.to2);this.data.dnd.to2=false}}}},this)).delegate("a","mouseup.jstree",$.proxy(function(e){if($.vakata.dnd.is_drag&&$.vakata.dnd.user_data.jstree){this.dnd_finish(e)}},this));$(document).bind("drag_stop.vakata",$.proxy(function(){this.data.dnd.after=false;this.data.dnd.before=false;this.data.dnd.inside=false;this.data.dnd.off=false;this.data.dnd.prepared=false;this.data.dnd.w=false;this.data.dnd.to1=false;this.data.dnd.to2=false;this.data.dnd.active=false;this.data.dnd.foreign=false;if(m){m.css({top:"-2000px"})}},this)).bind("drag_start.vakata",$.proxy(function(e,data){if(data.data.jstree){var et=$(data.event.target);if(et.closest(".jstree").hasClass("jstree-"+this.get_index())){this.dnd_enter(et)}}},this));var s=this._get_settings().dnd;if(s.drag_target){$(document).delegate(s.drag_target,"mousedown.jstree",$.proxy(function(e){o=e.target;$.vakata.dnd.drag_start(e,{jstree:true,obj:e.target},"<ins class='jstree-icon'></ins>"+$(e.target).text());if(this.data.themes){m.attr("class","jstree-"+this.data.themes.theme);$.vakata.dnd.helper.attr("class","jstree-dnd-helper jstree-"+this.data.themes.theme)}$.vakata.dnd.helper.children("ins").attr("class","jstree-invalid");var cnt=this.get_container();this.data.dnd.cof=cnt.offset();this.data.dnd.cw=parseInt(cnt.width(),10);this.data.dnd.ch=parseInt(cnt.height(),10);this.data.dnd.foreign=true;return false},this))}if(s.drop_target){$(document).delegate(s.drop_target,"mouseenter.jstree",$.proxy(function(e){if(this.data.dnd.active&&this._get_settings().dnd.drop_check.call(this,{o:o,r:$(e.target)})){$.vakata.dnd.helper.children("ins").attr("class","jstree-ok")}},this)).delegate(s.drop_target,"mouseleave.jstree",$.proxy(function(e){if(this.data.dnd.active){$.vakata.dnd.helper.children("ins").attr("class","jstree-invalid")}},this)).delegate(s.drop_target,"mouseup.jstree",$.proxy(function(e){if(this.data.dnd.active&&$.vakata.dnd.helper.children("ins").hasClass("jstree-ok")){this._get_settings().dnd.drop_finish.call(this,{o:o,r:$(e.target)})}},this))}},defaults:{copy_modifier:"ctrl",check_timeout:200,open_timeout:500,drop_target:".jstree-drop",drop_check:function(data){return true},drop_finish:$.noop,drag_target:".jstree-draggable",drag_finish:$.noop,drag_check:function(data){return{after:false,before:false,inside:true}}},_fn:{dnd_prepare:function(){if(!r||!r.length){return}this.data.dnd.off=r.offset();if(this._get_settings().core.rtl){this.data.dnd.off.right=this.data.dnd.off.left+r.width()}if(this.data.dnd.foreign){var a=this._get_settings().dnd.drag_check.call(this,{o:o,r:r});this.data.dnd.after=a.after;this.data.dnd.before=a.before;this.data.dnd.inside=a.inside;this.data.dnd.prepared=true;return this.dnd_show()}this.prepare_move(o,r,"before");this.data.dnd.before=this.check_move();this.prepare_move(o,r,"after");this.data.dnd.after=this.check_move();if(this._is_loaded(r)){this.prepare_move(o,r,"inside");this.data.dnd.inside=this.check_move()}else{this.data.dnd.inside=false}this.data.dnd.prepared=true;return this.dnd_show()},dnd_show:function(){if(!this.data.dnd.prepared){return}var o=["before","inside","after"],r=false,rtl=this._get_settings().core.rtl,pos;if(this.data.dnd.w<this.data.core.li_height/3){o=["before","inside","after"]}else{if(this.data.dnd.w<=this.data.core.li_height*2/3){o=this.data.dnd.w<this.data.core.li_height/2?["inside","before","after"]:["inside","after","before"]}else{o=["after","inside","before"]}}$.each(o,$.proxy(function(i,val){if(this.data.dnd[val]){$.vakata.dnd.helper.children("ins").attr("class","jstree-ok");r=val;return false}},this));if(r===false){$.vakata.dnd.helper.children("ins").attr("class","jstree-invalid")}pos=rtl?(this.data.dnd.off.right-18):(this.data.dnd.off.left+10);switch(r){case"before":m.css({left:pos+"px",top:(this.data.dnd.off.top-6)+"px"}).show();break;case"after":m.css({left:pos+"px",top:(this.data.dnd.off.top+this.data.core.li_height-7)+"px"}).show();break;case"inside":m.css({left:pos+(rtl?-4:4)+"px",top:(this.data.dnd.off.top+this.data.core.li_height/2-5)+"px"}).show();break;default:m.hide();break}return r},dnd_open:function(){this.data.dnd.to2=false;this.open_node(r,$.proxy(this.dnd_prepare,this),true)},dnd_finish:function(e){if(this.data.dnd.foreign){if(this.data.dnd.after||this.data.dnd.before||this.data.dnd.inside){this._get_settings().dnd.drag_finish.call(this,{o:o,r:r})}}else{this.dnd_prepare();this.move_node(o,r,this.dnd_show(),e[this._get_settings().dnd.copy_modifier+"Key"])}o=false;r=false;m.hide()},dnd_enter:function(obj){var s=this._get_settings().dnd;this.data.dnd.prepared=false;r=this._get_node(obj);if(s.check_timeout){if(this.data.dnd.to1){clearTimeout(this.data.dnd.to1)}this.data.dnd.to1=setTimeout($.proxy(this.dnd_prepare,this),s.check_timeout)}else{this.dnd_prepare()}if(s.open_timeout){if(this.data.dnd.to2){clearTimeout(this.data.dnd.to2)}if(r&&r.length&&r.hasClass("jstree-closed")){this.data.dnd.to2=setTimeout($.proxy(this.dnd_open,this),s.open_timeout)}}else{if(r&&r.length&&r.hasClass("jstree-closed")){this.dnd_open()}}},start_drag:function(obj,e){o=this._get_node(obj);if(this.data.ui&&this.is_selected(o)){o=this._get_node(null,true)}$.vakata.dnd.drag_start(e,{jstree:true,obj:o},"<ins class='jstree-icon'></ins>"+(o.length>1?"Multiple selection":this.get_text(o)));if(this.data.themes){m.attr("class","jstree-"+this.data.themes.theme);$.vakata.dnd.helper.attr("class","jstree-dnd-helper jstree-"+this.data.themes.theme)}var cnt=this.get_container();this.data.dnd.cof=cnt.children("ul").offset();this.data.dnd.cw=parseInt(cnt.width(),10);this.data.dnd.ch=parseInt(cnt.height(),10);this.data.dnd.active=true}}});$(function(){var css_string="#vakata-dragged ins { display:block; text-decoration:none; width:16px; height:16px; margin:0 0 0 0; padding:0; position:absolute; top:4px; left:4px; } #vakata-dragged .jstree-ok { background:green; } #vakata-dragged .jstree-invalid { background:red; } #jstree-marker { padding:0; margin:0; line-height:12px; font-size:1px; overflow:hidden; height:12px; width:8px; position:absolute; top:-30px; z-index:10000; background-repeat:no-repeat; display:none; background-color:silver; } ";$.vakata.css.add_sheet({str:css_string});m=$("<div>").attr({id:"jstree-marker"}).hide().appendTo("body");$(document).bind("drag_start.vakata",function(e,data){if(data.data.jstree){m.show()}});$(document).bind("drag_stop.vakata",function(e,data){if(data.data.jstree){m.hide()}})})})(jQuery);(function($){$.jstree.plugin("checkbox",{__init:function(){this.select_node=this.deselect_node=this.deselect_all=$.noop;this.get_selected=this.get_checked;this.get_container().bind("open_node.jstree create_node.jstree clean_node.jstree",$.proxy(function(e,data){this._prepare_checkboxes(data.rslt.obj)},this)).bind("loaded.jstree",$.proxy(function(e){this._prepare_checkboxes()},this)).delegate("a","click.jstree",$.proxy(function(e){if(this._get_node(e.target).hasClass("jstree-checked")){this.uncheck_node(e.target)}else{this.check_node(e.target)}if(this.data.ui){this.save_selected()}if(this.data.cookies){this.save_cookie("select_node")}e.preventDefault()},this))},__destroy:function(){this.get_container().find(".jstree-checkbox").remove()},_fn:{_prepare_checkboxes:function(obj){obj=!obj||obj==-1?this.get_container():this._get_node(obj);var c,_this=this,t;obj.each(function(){t=$(this);c=t.is("li")&&t.hasClass("jstree-checked")?"jstree-checked":"jstree-unchecked";t.find("a").not(":has(.jstree-checkbox)").prepend("<ins class='jstree-checkbox'>&#160;</ins>").parent().not(".jstree-checked, .jstree-unchecked").addClass(c)});if(obj.is("li")){this._repair_state(obj)}else{obj.find("> ul > li").each(function(){_this._repair_state(this)})}},change_state:function(obj,state){obj=this._get_node(obj);state=(state===false||state===true)?state:obj.hasClass("jstree-checked");if(state){obj.find("li").andSelf().removeClass("jstree-checked jstree-undetermined").addClass("jstree-unchecked")}else{obj.find("li").andSelf().removeClass("jstree-unchecked jstree-undetermined").addClass("jstree-checked");if(this.data.ui){this.data.ui.last_selected=obj}this.data.checkbox.last_selected=obj}obj.parentsUntil(".jstree","li").each(function(){var $this=$(this);if(state){if($this.children("ul").children(".jstree-checked, .jstree-undetermined").length){$this.parentsUntil(".jstree","li").andSelf().removeClass("jstree-checked jstree-unchecked").addClass("jstree-undetermined");return false}else{$this.removeClass("jstree-checked jstree-undetermined").addClass("jstree-unchecked")}}else{if($this.children("ul").children(".jstree-unchecked, .jstree-undetermined").length){$this.parentsUntil(".jstree","li").andSelf().removeClass("jstree-checked jstree-unchecked").addClass("jstree-undetermined");return false}else{$this.removeClass("jstree-unchecked jstree-undetermined").addClass("jstree-checked")}}});if(this.data.ui){this.data.ui.selected=this.get_checked()}this.__callback(obj)},check_node:function(obj){this.change_state(obj,false)},uncheck_node:function(obj){this.change_state(obj,true)},check_all:function(){var _this=this;this.get_container().children("ul").children("li").each(function(){_this.check_node(this,false)})},uncheck_all:function(){var _this=this;this.get_container().children("ul").children("li").each(function(){_this.change_state(this,true)})},is_checked:function(obj){obj=this._get_node(obj);return obj.length?obj.is(".jstree-checked"):false},get_checked:function(obj){obj=!obj||obj===-1?this.get_container():this._get_node(obj);return obj.find("> ul > .jstree-checked, .jstree-undetermined > ul > .jstree-checked")},get_unchecked:function(obj){obj=!obj||obj===-1?this.get_container():this._get_node(obj);return obj.find("> ul > .jstree-unchecked, .jstree-undetermined > ul > .jstree-unchecked")},show_checkboxes:function(){this.get_container().children("ul").removeClass("jstree-no-checkboxes")},hide_checkboxes:function(){this.get_container().children("ul").addClass("jstree-no-checkboxes")},_repair_state:function(obj){obj=this._get_node(obj);if(!obj.length){return}var a=obj.find("> ul > .jstree-checked").length,b=obj.find("> ul > .jstree-undetermined").length,c=obj.find("> ul > li").length;if(c===0){if(obj.hasClass("jstree-undetermined")){this.check_node(obj)}}else{if(a===0&&b===0){this.uncheck_node(obj)}else{if(a===c){this.check_node(obj)}else{obj.parentsUntil(".jstree","li").removeClass("jstree-checked jstree-unchecked").addClass("jstree-undetermined")}}}},reselect:function(){if(this.data.ui){var _this=this,s=this.data.ui.to_select;s=$.map($.makeArray(s),function(n){return"#"+n.toString().replace(/^#/,"").replace("\\/","/").replace("/","\\/")});this.deselect_all();$.each(s,function(i,val){_this.check_node(val)});this.__callback()}}}})})(jQuery);(function($){$.vakata.xslt=function(xml,xsl,callback){var rs="",xm,xs,processor,support;if(document.recalc){xm=document.createElement("xml");xs=document.createElement("xml");xm.innerHTML=xml;xs.innerHTML=xsl;$("body").append(xm).append(xs);setTimeout((function(xm,xs,callback){return function(){callback.call(null,xm.transformNode(xs.XMLDocument));setTimeout((function(xm,xs){return function(){jQuery("body").remove(xm).remove(xs)}})(xm,xs),200)}})(xm,xs,callback),100);return true}if(typeof window.DOMParser!=="undefined"&&typeof window.XMLHttpRequest!=="undefined"&&typeof window.XSLTProcessor!=="undefined"){processor=new XSLTProcessor();support=$.isFunction(processor.transformDocument)?(typeof window.XMLSerializer!=="undefined"):true;if(!support){return false}xml=new DOMParser().parseFromString(xml,"text/xml");xsl=new DOMParser().parseFromString(xsl,"text/xml");if($.isFunction(processor.transformDocument)){rs=document.implementation.createDocument("","",null);processor.transformDocument(xml,xsl,rs,null);callback.call(null,XMLSerializer().serializeToString(rs));return true}else{processor.importStylesheet(xsl);rs=processor.transformToFragment(xml,document);callback.call(null,$("<div>").append(rs).html());return true}}return false};var xsl={nest:'<?xml version="1.0" encoding="utf-8" ?><xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" ><xsl:output method="html" encoding="utf-8" omit-xml-declaration="yes" standalone="no" indent="no" media-type="text/html" /><xsl:template match="/"> <xsl:call-template name="nodes"> <xsl:with-param name="node" select="/root" /> </xsl:call-template></xsl:template><xsl:template name="nodes"> <xsl:param name="node" /> <ul> <xsl:for-each select="$node/item"> <xsl:variable name="children" select="count(./item) &gt; 0" /> <li> <xsl:attribute name="class"> <xsl:if test="position() = last()">jstree-last </xsl:if> <xsl:choose> <xsl:when test="@state = \'open\'">jstree-open </xsl:when> <xsl:when test="$children or @hasChildren or @state = \'closed\'">jstree-closed </xsl:when> <xsl:otherwise>jstree-leaf </xsl:otherwise> </xsl:choose> <xsl:value-of select="@class" /> </xsl:attribute> <xsl:for-each select="@*"> <xsl:if test="name() != \'class\' and name() != \'state\' and name() != \'hasChildren\'"> <xsl:attribute name="{name()}"><xsl:value-of select="." /></xsl:attribute> </xsl:if> </xsl:for-each> <ins class="jstree-icon"><xsl:text>&#xa0;</xsl:text></ins> <xsl:for-each select="content/name"> <a> <xsl:attribute name="href"> <xsl:choose> <xsl:when test="@href"><xsl:value-of select="@href" /></xsl:when> <xsl:otherwise>#</xsl:otherwise> </xsl:choose> </xsl:attribute> <xsl:attribute name="class"><xsl:value-of select="@lang" /> <xsl:value-of select="@class" /></xsl:attribute> <xsl:attribute name="style"><xsl:value-of select="@style" /></xsl:attribute> <xsl:for-each select="@*"> <xsl:if test="name() != \'style\' and name() != \'class\' and name() != \'href\'"> <xsl:attribute name="{name()}"><xsl:value-of select="." /></xsl:attribute> </xsl:if> </xsl:for-each> <ins> <xsl:attribute name="class">jstree-icon <xsl:if test="string-length(attribute::icon) > 0 and not(contains(@icon,\'/\'))"><xsl:value-of select="@icon" /></xsl:if> </xsl:attribute> <xsl:if test="string-length(attribute::icon) > 0 and contains(@icon,\'/\')"><xsl:attribute name="style">background:url(<xsl:value-of select="@icon" />) center center no-repeat;</xsl:attribute></xsl:if> <xsl:text>&#xa0;</xsl:text> </ins> <xsl:value-of select="current()" /> </a> </xsl:for-each> <xsl:if test="$children or @hasChildren"><xsl:call-template name="nodes"><xsl:with-param name="node" select="current()" /></xsl:call-template></xsl:if> </li> </xsl:for-each> </ul></xsl:template></xsl:stylesheet>',flat:'<?xml version="1.0" encoding="utf-8" ?><xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" ><xsl:output method="html" encoding="utf-8" omit-xml-declaration="yes" standalone="no" indent="no" media-type="text/xml" /><xsl:template match="/"> <ul> <xsl:for-each select="//item[not(@parent_id) or @parent_id=0 or not(@parent_id = //item/@id)]"> <xsl:call-template name="nodes"> <xsl:with-param name="node" select="." /> <xsl:with-param name="is_last" select="number(position() = last())" /> </xsl:call-template> </xsl:for-each> </ul></xsl:template><xsl:template name="nodes"> <xsl:param name="node" /> <xsl:param name="is_last" /> <xsl:variable name="children" select="count(//item[@parent_id=$node/attribute::id]) &gt; 0" /> <li> <xsl:attribute name="class"> <xsl:if test="$is_last = true()">jstree-last </xsl:if> <xsl:choose> <xsl:when test="@state = \'open\'">jstree-open </xsl:when> <xsl:when test="$children or @hasChildren or @state = \'closed\'">jstree-closed </xsl:when> <xsl:otherwise>jstree-leaf </xsl:otherwise> </xsl:choose> <xsl:value-of select="@class" /> </xsl:attribute> <xsl:for-each select="@*"> <xsl:if test="name() != \'parent_id\' and name() != \'hasChildren\' and name() != \'class\' and name() != \'state\'"> <xsl:attribute name="{name()}"><xsl:value-of select="." /></xsl:attribute> </xsl:if> </xsl:for-each> <ins class="jstree-icon"><xsl:text>&#xa0;</xsl:text></ins> <xsl:for-each select="content/name"> <a> <xsl:attribute name="href"> <xsl:choose> <xsl:when test="@href"><xsl:value-of select="@href" /></xsl:when> <xsl:otherwise>#</xsl:otherwise> </xsl:choose> </xsl:attribute> <xsl:attribute name="class"><xsl:value-of select="@lang" /> <xsl:value-of select="@class" /></xsl:attribute> <xsl:attribute name="style"><xsl:value-of select="@style" /></xsl:attribute> <xsl:for-each select="@*"> <xsl:if test="name() != \'style\' and name() != \'class\' and name() != \'href\'"> <xsl:attribute name="{name()}"><xsl:value-of select="." /></xsl:attribute> </xsl:if> </xsl:for-each> <ins> <xsl:attribute name="class">jstree-icon <xsl:if test="string-length(attribute::icon) > 0 and not(contains(@icon,\'/\'))"><xsl:value-of select="@icon" /></xsl:if> </xsl:attribute> <xsl:if test="string-length(attribute::icon) > 0 and contains(@icon,\'/\')"><xsl:attribute name="style">background:url(<xsl:value-of select="@icon" />) center center no-repeat;</xsl:attribute></xsl:if> <xsl:text>&#xa0;</xsl:text> </ins> <xsl:value-of select="current()" /> </a> </xsl:for-each> <xsl:if test="$children"> <ul> <xsl:for-each select="//item[@parent_id=$node/attribute::id]"> <xsl:call-template name="nodes"> <xsl:with-param name="node" select="." /> <xsl:with-param name="is_last" select="number(position() = last())" /> </xsl:call-template> </xsl:for-each> </ul> </xsl:if> </li></xsl:template></xsl:stylesheet>'};$.jstree.plugin("xml_data",{defaults:{data:false,ajax:false,xsl:"flat",clean_node:false,correct_state:true},_fn:{load_node:function(obj,s_call,e_call){var _this=this;this.load_node_xml(obj,function(){_this.__callback({obj:obj});s_call.call(this)},e_call)},_is_loaded:function(obj){var s=this._get_settings().xml_data;obj=this._get_node(obj);return obj==-1||!obj||!s.ajax||obj.is(".jstree-open, .jstree-leaf")||obj.children("ul").children("li").size()>0},load_node_xml:function(obj,s_call,e_call){var s=this.get_settings().xml_data,error_func=function(){},success_func=function(){};obj=this._get_node(obj);if(obj&&obj!==-1){if(obj.data("jstree-is-loading")){return}else{obj.data("jstree-is-loading",true)}}switch(!0){case (!s.data&&!s.ajax):throw"Neither data nor ajax settings supplied.";case (!!s.data&&!s.ajax)||(!!s.data&&!!s.ajax&&(!obj||obj===-1)):if(!obj||obj==-1){this.parse_xml(s.data,$.proxy(function(d){if(d){d=d.replace(/ ?xmlns="[^"]*"/ig,"");if(d.length>10){d=$(d);this.get_container().children("ul").empty().append(d.children());if(s.clean_node){this.clean_node(obj)}if(s_call){s_call.call(this)}}}else{if(s.correct_state){this.get_container().children("ul").empty();if(s_call){s_call.call(this)}}}},this))}break;case (!s.data&&!!s.ajax)||(!!s.data&&!!s.ajax&&obj&&obj!==-1):error_func=function(x,t,e){var ef=this.get_settings().xml_data.ajax.error;if(ef){ef.call(this,x,t,e)}if(obj!==-1&&obj.length){obj.children(".jstree-loading").removeClass("jstree-loading");obj.data("jstree-is-loading",false);if(t==="success"&&s.correct_state){obj.removeClass("jstree-open jstree-closed").addClass("jstree-leaf")}}else{if(t==="success"&&s.correct_state){this.get_container().children("ul").empty()}}if(e_call){e_call.call(this)}};success_func=function(d,t,x){d=x.responseText;var sf=this.get_settings().xml_data.ajax.success;if(sf){d=sf.call(this,d,t,x)||d}if(d==""){return error_func.call(this,x,t,"")}this.parse_xml(d,$.proxy(function(d){if(d){d=d.replace(/ ?xmlns="[^"]*"/ig,"");if(d.length>10){d=$(d);if(obj===-1||!obj){this.get_container().children("ul").empty().append(d.children())}else{obj.children(".jstree-loading").removeClass("jstree-loading");obj.append(d);obj.data("jstree-is-loading",false)}if(s.clean_node){this.clean_node(obj)}if(s_call){s_call.call(this)}}else{if(obj&&obj!==-1){obj.children(".jstree-loading").removeClass("jstree-loading");obj.data("jstree-is-loading",false);if(s.correct_state){obj.removeClass("jstree-open jstree-closed").addClass("jstree-leaf");if(s_call){s_call.call(this)}}}else{if(s.correct_state){this.get_container().children("ul").empty();if(s_call){s_call.call(this)}}}}}},this))};s.ajax.context=this;s.ajax.error=error_func;s.ajax.success=success_func;if(!s.ajax.dataType){s.ajax.dataType="xml"}if($.isFunction(s.ajax.url)){s.ajax.url=s.ajax.url.call(this,obj)}if($.isFunction(s.ajax.data)){s.ajax.data=s.ajax.data.call(this,obj)}$.ajax(s.ajax);break}},parse_xml:function(xml,callback){var s=this._get_settings().xml_data;$.vakata.xslt(xml,xsl[s.xsl],callback)},get_xml:function(tp,obj,li_attr,a_attr,is_callback){var result="",s=this._get_settings(),_this=this,tmp1,tmp2,li,a,lang;if(!tp){tp="flat"}if(!is_callback){is_callback=0}obj=this._get_node(obj);if(!obj||obj===-1){obj=this.get_container().find("> ul > li")}li_attr=$.isArray(li_attr)?li_attr:["id","class"];if(!is_callback&&this.data.types&&$.inArray(s.types.type_attr,li_attr)===-1){li_attr.push(s.types.type_attr)}a_attr=$.isArray(a_attr)?a_attr:[];if(!is_callback){result+="<root>"}obj.each(function(){result+="<item";li=$(this);$.each(li_attr,function(i,v){result+=" "+v+'="'+(li.attr(v)||"").replace(/jstree[^ ]*|$/ig,"").replace(/^\s+$/ig,"")+'"'});if(li.hasClass("jstree-open")){result+=' state="open"'}if(li.hasClass("jstree-closed")){result+=' state="closed"'}if(tp==="flat"){result+=' parent_id="'+is_callback+'"'}result+=">";result+="<content>";a=li.children("a");a.each(function(){tmp1=$(this);lang=false;result+="<name";if($.inArray("languages",s.plugins)!==-1){$.each(s.languages,function(k,z){if(tmp1.hasClass(z)){result+=' lang="'+z+'"';lang=z;return false}})}if(a_attr.length){$.each(a_attr,function(k,z){result+=" "+z+'="'+(tmp1.attr(z)||"").replace(/jstree[^ ]*|$/ig,"")+'"'})}if(tmp1.children("ins").get(0).className.replace(/jstree[^ ]*|$/ig,"").replace(/^\s+$/ig,"").length){result+=' icon="'+tmp1.children("ins").get(0).className.replace(/jstree[^ ]*|$/ig,"").replace(/^\s+$/ig,"")+'"'}if(tmp1.children("ins").get(0).style.backgroundImage.length){result+=' icon="'+tmp1.children("ins").get(0).style.backgroundImage.replace("url(","").replace(")","")+'"'}result+=">";result+="<![CDATA["+_this.get_text(tmp1,lang)+"]]>";result+="</name>"});result+="</content>";tmp2=li[0].id;li=li.find("> ul > li");if(li.length){tmp2=_this.get_xml(tp,li,li_attr,a_attr,tmp2)}else{tmp2=""}if(tp=="nest"){result+=tmp2}result+="</item>";if(tp=="flat"){result+=tmp2}});if(!is_callback){result+="</root>"}return result}}})})(jQuery);(function($){$.expr[":"].jstree_contains=function(a,i,m){return(a.textContent||a.innerText||"").toLowerCase().indexOf(m[3].toLowerCase())>=0};$.jstree.plugin("search",{__init:function(){this.data.search.str="";this.data.search.result=$()},defaults:{ajax:false,case_insensitive:false},_fn:{search:function(str,skip_async){if(str===""){return}var s=this.get_settings().search,t=this,error_func=function(){},success_func=function(){};this.data.search.str=str;if(!skip_async&&s.ajax!==false&&this.get_container().find(".jstree-closed:eq(0)").length>0){this.search.supress_callback=true;error_func=function(){};success_func=function(d,t,x){var sf=this.get_settings().search.ajax.success;if(sf){d=sf.call(this,d,t,x)||d}this.data.search.to_open=d;this._search_open()};s.ajax.context=this;s.ajax.error=error_func;s.ajax.success=success_func;if($.isFunction(s.ajax.url)){s.ajax.url=s.ajax.url.call(this,str)}if($.isFunction(s.ajax.data)){s.ajax.data=s.ajax.data.call(this,str)}if(!s.ajax.data){s.ajax.data={search_string:str}}if(!s.ajax.dataType||/^json/.exec(s.ajax.dataType)){s.ajax.dataType="json"}$.ajax(s.ajax);return}if(this.data.search.result.length){this.clear_search()}this.data.search.result=this.get_container().find("a"+(this.data.languages?"."+this.get_lang():"")+":"+(s.case_insensitive?"jstree_contains":"contains")+"("+this.data.search.str+")");this.data.search.result.addClass("jstree-search").parents(".jstree-closed").each(function(){t.open_node(this,false,true)});this.__callback({nodes:this.data.search.result,str:str})},clear_search:function(str){this.data.search.result.removeClass("jstree-search");this.__callback(this.data.search.result);this.data.search.result=$()},_search_open:function(is_callback){var _this=this,done=true,current=[],remaining=[];if(this.data.search.to_open.length){$.each(this.data.search.to_open,function(i,val){if(val=="#"){return true}if($(val).length&&$(val).is(".jstree-closed")){current.push(val)}else{remaining.push(val)}});if(current.length){this.data.search.to_open=remaining;$.each(current,function(i,val){_this.open_node(val,function(){_this._search_open(true)})});done=false}}if(done){this.search(this.data.search.str,true)}}}})})(jQuery);(function($){$.vakata.context={cnt:$("<div id='vakata-contextmenu'/>"),vis:false,tgt:false,par:false,func:false,data:false,show:function(s,t,x,y,d,p){var html=$.vakata.context.parse(s),h,w;if(!html){return}$.vakata.context.vis=true;$.vakata.context.tgt=t;$.vakata.context.par=p||t||null;$.vakata.context.data=d||null;$.vakata.context.cnt.html(html).css({visibility:"hidden",display:"block",left:0,top:0});h=$.vakata.context.cnt.height();w=$.vakata.context.cnt.width();if(x+w>$(document).width()){x=$(document).width()-(w+5);$.vakata.context.cnt.find("li > ul").addClass("right")}if(y+h>$(document).height()){y=y-(h+t[0].offsetHeight);$.vakata.context.cnt.find("li > ul").addClass("bottom")}$.vakata.context.cnt.css({left:x,top:y}).find("li:has(ul)").bind("mouseenter",function(e){var w=$(document).width(),h=$(document).height(),ul=$(this).children("ul").show();if(w!==$(document).width()){ul.toggleClass("right")}if(h!==$(document).height()){ul.toggleClass("bottom")}}).bind("mouseleave",function(e){$(this).children("ul").hide()}).end().css({visibility:"visible"}).show();$(document).triggerHandler("context_show.vakata")},hide:function(){$.vakata.context.vis=false;$.vakata.context.cnt.attr("class","").hide();$(document).triggerHandler("context_hide.vakata")},parse:function(s,is_callback){if(!s){return false}var str="",tmp=false,was_sep=true;if(!is_callback){$.vakata.context.func={}}str+="<ul>";$.each(s,function(i,val){if(!val){return true}$.vakata.context.func[i]=val.action;if(!was_sep&&val.separator_before){str+="<li class='vakata-separator vakata-separator-before'></li>"}was_sep=false;str+="<li class='"+(val._class||"")+(val._disabled?" jstree-contextmenu-disabled ":"")+"'><ins ";if(val.icon&&val.icon.indexOf("/")===-1){str+=" class='"+val.icon+"' "}if(val.icon&&val.icon.indexOf("/")!==-1){str+=" style='background:url("+val.icon+") center center no-repeat;' "}str+=">&#160;</ins><a href='#' rel='"+i+"'>";if(val.submenu){str+="<span style='float:right;'>&raquo;</span>"}str+=val.label+"</a>";if(val.submenu){tmp=$.vakata.context.parse(val.submenu,true);if(tmp){str+=tmp}}str+="</li>";if(val.separator_after){str+="<li class='vakata-separator vakata-separator-after'></li>";was_sep=true}});str=str.replace(/<li class\='vakata-separator vakata-separator-after'\><\/li\>$/,"");str+="</ul>";return str.length>10?str:false},exec:function(i){if($.isFunction($.vakata.context.func[i])){$.vakata.context.func[i].call($.vakata.context.data,$.vakata.context.par);return true}else{return false}}};$(function(){var css_string="#vakata-contextmenu { display:none; position:absolute; margin:0; padding:0; min-width:180px; background:#ebebeb; border:1px solid silver; z-index:10000; *width:180px; } #vakata-contextmenu ul { min-width:180px; *width:180px; } #vakata-contextmenu ul, #vakata-contextmenu li { margin:0; padding:0; list-style-type:none; display:block; } #vakata-contextmenu li { line-height:20px; min-height:20px; position:relative; padding:0px; } #vakata-contextmenu li a { padding:1px 6px; line-height:17px; display:block; text-decoration:none; margin:1px 1px 0 1px; } #vakata-contextmenu li ins { float:left; width:16px; height:16px; text-decoration:none; margin-right:2px; } #vakata-contextmenu li a:hover, #vakata-contextmenu li.vakata-hover > a { background:gray; color:white; } #vakata-contextmenu li ul { display:none; position:absolute; top:-2px; left:100%; background:#ebebeb; border:1px solid gray; } #vakata-contextmenu .right { right:100%; left:auto; } #vakata-contextmenu .bottom { bottom:-1px; top:auto; } #vakata-contextmenu li.vakata-separator { min-height:0; height:1px; line-height:1px; font-size:1px; overflow:hidden; margin:0 2px; background:silver; /* border-top:1px solid #fefefe; */ padding:0; } ";$.vakata.css.add_sheet({str:css_string});$.vakata.context.cnt.delegate("a","click",function(e){e.preventDefault()}).delegate("a","mouseup",function(e){if(!$(this).parent().hasClass("jstree-contextmenu-disabled")&&$.vakata.context.exec($(this).attr("rel"))){$.vakata.context.hide()}else{$(this).blur()}}).delegate("a","mouseover",function(){$.vakata.context.cnt.find(".vakata-hover").removeClass("vakata-hover")}).appendTo("body");$(document).bind("mousedown",function(e){if($.vakata.context.vis&&!$.contains($.vakata.context.cnt[0],e.target)){$.vakata.context.hide()}});if(typeof $.hotkeys!=="undefined"){$(document).bind("keydown","up",function(e){if($.vakata.context.vis){var o=$.vakata.context.cnt.find("ul:visible").last().children(".vakata-hover").removeClass("vakata-hover").prevAll("li:not(.vakata-separator)").first();if(!o.length){o=$.vakata.context.cnt.find("ul:visible").last().children("li:not(.vakata-separator)").last()}o.addClass("vakata-hover");e.stopImmediatePropagation();e.preventDefault()}}).bind("keydown","down",function(e){if($.vakata.context.vis){var o=$.vakata.context.cnt.find("ul:visible").last().children(".vakata-hover").removeClass("vakata-hover").nextAll("li:not(.vakata-separator)").first();if(!o.length){o=$.vakata.context.cnt.find("ul:visible").last().children("li:not(.vakata-separator)").first()}o.addClass("vakata-hover");e.stopImmediatePropagation();e.preventDefault()}}).bind("keydown","right",function(e){if($.vakata.context.vis){$.vakata.context.cnt.find(".vakata-hover").children("ul").show().children("li:not(.vakata-separator)").removeClass("vakata-hover").first().addClass("vakata-hover");e.stopImmediatePropagation();e.preventDefault()}}).bind("keydown","left",function(e){if($.vakata.context.vis){$.vakata.context.cnt.find(".vakata-hover").children("ul").hide().children(".vakata-separator").removeClass("vakata-hover");e.stopImmediatePropagation();e.preventDefault()}}).bind("keydown","esc",function(e){$.vakata.context.hide();e.preventDefault()}).bind("keydown","space",function(e){$.vakata.context.cnt.find(".vakata-hover").last().children("a").click();e.preventDefault()})}});$.jstree.plugin("contextmenu",{__init:function(){this.get_container().delegate("a","contextmenu.jstree",$.proxy(function(e){e.preventDefault();this.show_contextmenu(e.currentTarget,e.pageX,e.pageY)},this)).bind("destroy.jstree",$.proxy(function(){if(this.data.contextmenu){$.vakata.context.hide()}},this));$(document).bind("context_hide.vakata",$.proxy(function(){this.data.contextmenu=false},this))},defaults:{select_node:false,show_at_node:true,items:{create:{separator_before:false,separator_after:true,label:"Create",action:function(obj){this.create(obj)}},rename:{separator_before:false,separator_after:false,label:"Rename",action:function(obj){this.rename(obj)}},remove:{separator_before:false,icon:false,separator_after:false,label:"Delete",action:function(obj){this.remove(obj)}},ccp:{separator_before:true,icon:false,separator_after:false,label:"Edit",action:false,submenu:{cut:{separator_before:false,separator_after:false,label:"Cut",action:function(obj){this.cut(obj)}},copy:{separator_before:false,icon:false,separator_after:false,label:"Copy",action:function(obj){this.copy(obj)}},paste:{separator_before:false,icon:false,separator_after:false,label:"Paste",action:function(obj){this.paste(obj)}}}}}},_fn:{show_contextmenu:function(obj,x,y){obj=this._get_node(obj);var s=this.get_settings().contextmenu,a=obj.children("a:visible:eq(0)"),o=false;if(s.select_node&&this.data.ui&&!this.is_selected(obj)){this.deselect_all();this.select_node(obj,true)}if(s.show_at_node||typeof x==="undefined"||typeof y==="undefined"){o=a.offset();x=o.left;y=o.top+this.data.core.li_height}if($.isFunction(s.items)){s.items=s.items.call(this,obj)}this.data.contextmenu=true;$.vakata.context.show(s.items,a,x,y,this,obj);if(this.data.themes){$.vakata.context.cnt.attr("class","jstree-"+this.data.themes.theme+"-context")}}}})})(jQuery);(function($){$.jstree.plugin("types",{__init:function(){var s=this._get_settings().types;this.data.types.attach_to=[];this.get_container().bind("init.jstree",$.proxy(function(){var types=s.types,attr=s.type_attr,icons_css="",_this=this;$.each(types,function(i,tp){$.each(tp,function(k,v){if(!/^(max_depth|max_children|icon|valid_children)$/.test(k)){_this.data.types.attach_to.push(k)}});if(!tp.icon){return true}if(tp.icon.image||tp.icon.position){if(i=="default"){icons_css+=".jstree-"+_this.get_index()+" a > .jstree-icon { "}else{icons_css+=".jstree-"+_this.get_index()+" li["+attr+"="+i+"] > a > .jstree-icon { "}if(tp.icon.image){icons_css+=" background-image:url("+tp.icon.image+"); "}if(tp.icon.position){icons_css+=" background-position:"+tp.icon.position+"; "}else{icons_css+=" background-position:0 0; "}icons_css+="} "}});if(icons_css!=""){$.vakata.css.add_sheet({str:icons_css})}},this)).bind("before.jstree",$.proxy(function(e,data){if($.inArray(data.func,this.data.types.attach_to)!==-1){var s=this._get_settings().types.types,t=this._get_type(data.args[0]);if(((s[t]&&typeof s[t][data.func]!=="undefined")||(s["default"]&&typeof s["default"][data.func]!=="undefined"))&&!this._check(data.func,data.args[0])){e.stopImmediatePropagation();return false}}},this))},defaults:{max_children:-1,max_depth:-1,valid_children:"all",type_attr:"rel",types:{"default":{max_children:-1,max_depth:-1,valid_children:"all"}}},_fn:{_get_type:function(obj){obj=this._get_node(obj);return(!obj||!obj.length)?false:obj.attr(this._get_settings().types.type_attr)||"default"},set_type:function(str,obj){obj=this._get_node(obj);return(!obj.length||!str)?false:obj.attr(this._get_settings().types.type_attr,str)},_check:function(rule,obj,opts){var v=false,t=this._get_type(obj),d=0,_this=this,s=this._get_settings().types;if(obj===-1){if(!!s[rule]){v=s[rule]}else{return}}else{if(t===false){return}if(!!s.types[t]&&!!s.types[t][rule]){v=s.types[t][rule]}else{if(!!s.types["default"]&&!!s.types["default"][rule]){v=s.types["default"][rule]}}}if($.isFunction(v)){v=v.call(this,obj)}if(rule==="max_depth"&&obj!==-1&&opts!==false&&s.max_depth!==-2&&v!==0){this._get_node(obj).children("a:eq(0)").parentsUntil(".jstree","li").each(function(i){if(s.max_depth!==-1&&s.max_depth-(i+1)<=0){v=0;return false}d=(i===0)?v:_this._check(rule,this,false);if(d!==-1&&d-(i+1)<=0){v=0;return false}if(d>=0&&(d-(i+1)<v||v<0)){v=d-(i+1)}if(s.max_depth>=0&&(s.max_depth-(i+1)<v||v<0)){v=s.max_depth-(i+1)}})}return v},check_move:function(){if(!this.__call_old()){return false}var m=this._get_move(),s=m.rt._get_settings().types,mc=m.rt._check("max_children",m.cr),md=m.rt._check("max_depth",m.cr),vc=m.rt._check("valid_children",m.cr),ch=0,d=1,t;if(vc==="none"){return false}if($.isArray(vc)&&m.ot&&m.ot._get_type){m.o.each(function(){if($.inArray(m.ot._get_type(this),vc)===-1){d=false;return false}});if(d===false){return false}}if(s.max_children!==-2&&mc!==-1){ch=m.cr===-1?this.get_container().children("> ul > li").not(m.o).length:m.cr.children("> ul > li").not(m.o).length;if(ch+m.o.length>mc){return false}}if(s.max_depth!==-2&&md!==-1){d=0;if(md===0){return false}if(typeof m.o.d==="undefined"){t=m.o;while(t.length>0){t=t.find("> ul > li");d++}m.o.d=d}if(md-m.o.d<0){return false}}return true},create_node:function(obj,position,js,callback,is_loaded,skip_check){if(!skip_check&&(is_loaded||this._is_loaded(obj))){var p=(position&&position.match(/^before|after$/i)&&obj!==-1)?this._get_parent(obj):this._get_node(obj),s=this._get_settings().types,mc=this._check("max_children",p),md=this._check("max_depth",p),vc=this._check("valid_children",p),ch;if(!js){js={}}if(vc==="none"){return false}if($.isArray(vc)){if(!js.attr||!js.attr[s.type_attr]){if(!js.attr){js.attr={}}js.attr[s.type_attr]=vc[0]}else{if($.inArray(js.attr[s.type_attr],vc)===-1){return false}}}if(s.max_children!==-2&&mc!==-1){ch=p===-1?this.get_container().children("> ul > li").length:p.children("> ul > li").length;if(ch+1>mc){return false}}if(s.max_depth!==-2&&md!==-1&&(md-1)<0){return false}}return this.__call_old(true,obj,position,js,callback,is_loaded,skip_check)}}})})(jQuery);(function($){$.jstree.plugin("html_data",{__init:function(){this.data.html_data.original_container_html=this.get_container().find(" > ul > li").clone(true);this.data.html_data.original_container_html.find("li").andSelf().contents().filter(function(){return this.nodeType==3}).remove()},defaults:{data:false,ajax:false,correct_state:true},_fn:{load_node:function(obj,s_call,e_call){var _this=this;this.load_node_html(obj,function(){_this.__callback({obj:obj});s_call.call(this)},e_call)},_is_loaded:function(obj){obj=this._get_node(obj);return obj==-1||!obj||!this._get_settings().html_data.ajax||obj.is(".jstree-open, .jstree-leaf")||obj.children("ul").children("li").size()>0},load_node_html:function(obj,s_call,e_call){var d,s=this.get_settings().html_data,error_func=function(){},success_func=function(){};obj=this._get_node(obj);if(obj&&obj!==-1){if(obj.data("jstree-is-loading")){return}else{obj.data("jstree-is-loading",true)}}switch(!0){case (!s.data&&!s.ajax):if(!obj||obj==-1){this.get_container().children("ul").empty().append(this.data.html_data.original_container_html).find("li, a").filter(function(){return this.firstChild.tagName!=="INS"}).prepend("<ins class='jstree-icon'>&#160;</ins>").end().filter("a").children("ins:first-child").not(".jstree-icon").addClass("jstree-icon");this.clean_node()}if(s_call){s_call.call(this)}break;case (!!s.data&&!s.ajax)||(!!s.data&&!!s.ajax&&(!obj||obj===-1)):if(!obj||obj==-1){d=$(s.data);if(!d.is("ul")){d=$("<ul>").append(d)}this.get_container().children("ul").empty().append(d.children()).find("li, a").filter(function(){return this.firstChild.tagName!=="INS"}).prepend("<ins class='jstree-icon'>&#160;</ins>").end().filter("a").children("ins:first-child").not(".jstree-icon").addClass("jstree-icon");this.clean_node()}if(s_call){s_call.call(this)}break;case (!s.data&&!!s.ajax)||(!!s.data&&!!s.ajax&&obj&&obj!==-1):obj=this._get_node(obj);error_func=function(x,t,e){var ef=this.get_settings().html_data.ajax.error;if(ef){ef.call(this,x,t,e)}if(obj!=-1&&obj.length){obj.children(".jstree-loading").removeClass("jstree-loading");obj.data("jstree-is-loading",false);if(t==="success"&&s.correct_state){obj.removeClass("jstree-open jstree-closed").addClass("jstree-leaf")}}else{if(t==="success"&&s.correct_state){this.get_container().children("ul").empty()}}if(e_call){e_call.call(this)}};success_func=function(d,t,x){var sf=this.get_settings().html_data.ajax.success;if(sf){d=sf.call(this,d,t,x)||d}if(d==""){return error_func.call(this,x,t,"")}if(d){d=$(d);if(!d.is("ul")){d=$("<ul>").append(d)}if(obj==-1||!obj){this.get_container().children("ul").empty().append(d.children()).find("li, a").filter(function(){return this.firstChild.tagName!=="INS"}).prepend("<ins class='jstree-icon'>&#160;</ins>").end().filter("a").children("ins:first-child").not(".jstree-icon").addClass("jstree-icon")}else{obj.children(".jstree-loading").removeClass("jstree-loading");obj.append(d).find("li, a").filter(function(){return this.firstChild.tagName!=="INS"}).prepend("<ins class='jstree-icon'>&#160;</ins>").end().filter("a").children("ins:first-child").not(".jstree-icon").addClass("jstree-icon");obj.data("jstree-is-loading",false)}this.clean_node(obj);if(s_call){s_call.call(this)}}else{if(obj&&obj!==-1){obj.children(".jstree-loading").removeClass("jstree-loading");obj.data("jstree-is-loading",false);if(s.correct_state){obj.removeClass("jstree-open jstree-closed").addClass("jstree-leaf");if(s_call){s_call.call(this)}}}else{if(s.correct_state){this.get_container().children("ul").empty();if(s_call){s_call.call(this)}}}}};s.ajax.context=this;s.ajax.error=error_func;s.ajax.success=success_func;if(!s.ajax.dataType){s.ajax.dataType="html"}if($.isFunction(s.ajax.url)){s.ajax.url=s.ajax.url.call(this,obj)}if($.isFunction(s.ajax.data)){s.ajax.data=s.ajax.data.call(this,obj)}$.ajax(s.ajax);break}}}});$.jstree.defaults.plugins.push("html_data")})(jQuery);(function($){$.jstree.plugin("themeroller",{__init:function(){var s=this._get_settings().themeroller;this.get_container().addClass("ui-widget-content").delegate("a","mouseenter.jstree",function(){$(this).addClass(s.item_h)}).delegate("a","mouseleave.jstree",function(){$(this).removeClass(s.item_h)}).bind("open_node.jstree create_node.jstree",$.proxy(function(e,data){this._themeroller(data.rslt.obj)},this)).bind("loaded.jstree refresh.jstree",$.proxy(function(e){this._themeroller()},this)).bind("close_node.jstree",$.proxy(function(e,data){data.rslt.obj.children("ins").removeClass(s.opened).addClass(s.closed)},this)).bind("select_node.jstree",$.proxy(function(e,data){data.rslt.obj.children("a").addClass(s.item_a)},this)).bind("deselect_node.jstree deselect_all.jstree",$.proxy(function(e,data){this.get_container().find("."+s.item_a).removeClass(s.item_a).end().find(".jstree-clicked").addClass(s.item_a)},this)).bind("move_node.jstree",$.proxy(function(e,data){this._themeroller(data.rslt.o)},this))},__destroy:function(){var s=this._get_settings().themeroller,c=["ui-icon"];$.each(s,function(i,v){v=v.split(" ");if(v.length){c=c.concat(v)}});this.get_container().removeClass("ui-widget-content").find("."+c.join(", .")).removeClass(c.join(" "))},_fn:{_themeroller:function(obj){var s=this._get_settings().themeroller;obj=!obj||obj==-1?this.get_container():this._get_node(obj).parent();obj.find("li.jstree-closed > ins.jstree-icon").removeClass(s.opened).addClass("ui-icon "+s.closed).end().find("li.jstree-open > ins.jstree-icon").removeClass(s.closed).addClass("ui-icon "+s.opened).end().find("a").addClass(s.item).children("ins.jstree-icon").addClass("ui-icon "+s.item_icon)}},defaults:{opened:"ui-icon-triangle-1-se",closed:"ui-icon-triangle-1-e",item:"ui-state-default",item_h:"ui-state-hover",item_a:"ui-state-active",item_icon:"ui-icon-folder-collapsed"}});$(function(){var css_string=".jstree .ui-icon { overflow:visible; } .jstree a { padding:0 2px; }";$.vakata.css.add_sheet({str:css_string})})})(jQuery);(function($){$.jstree.plugin("unique",{__init:function(){this.get_container().bind("before.jstree",$.proxy(function(e,data){var nms=[],res=true,p,t;if(data.func=="move_node"){if(data.args[4]===true){if(data.args[0].o&&data.args[0].o.length){data.args[0].o.children("a").each(function(){nms.push($(this).text().replace(/^\s+/g,""))});res=this._check_unique(nms,data.args[0].np.find("> ul > li").not(data.args[0].o))}}}if(data.func=="create_node"){if(data.args[4]||this._is_loaded(data.args[0])){p=this._get_node(data.args[0]);if(data.args[1]&&(data.args[1]==="before"||data.args[1]==="after")){p=this._get_parent(data.args[0]);if(!p||p===-1){p=this.get_container()}}if(typeof data.args[2]==="string"){nms.push(data.args[2])}else{if(!data.args[2]||!data.args[2].data){nms.push(this._get_settings().core.strings.new_node)}else{nms.push(data.args[2].data)}}res=this._check_unique(nms,p.find("> ul > li"))}}if(data.func=="rename_node"){nms.push(data.args[1]);t=this._get_node(data.args[0]);p=this._get_parent(t);if(!p||p===-1){p=this.get_container()}res=this._check_unique(nms,p.find("> ul > li").not(t))}if(!res){e.stopPropagation();return false}},this))},_fn:{_check_unique:function(nms,p){var cnms=[];p.children("a").each(function(){cnms.push($(this).text().replace(/^\s+/g,""))});if(!cnms.length||!nms.length){return true}cnms=cnms.sort().join(",,").replace(/(,|^)([^,]+)(,,\2)+(,|$)/g,"$1$2$4").replace(/,,+/g,",").replace(/,$/,"").split(",");if((cnms.length+nms.length)!=cnms.concat(nms).sort().join(",,").replace(/(,|^)([^,]+)(,,\2)+(,|$)/g,"$1$2$4").replace(/,,+/g,",").replace(/,$/,"").split(",").length){return false}return true},check_move:function(){if(!this.__call_old()){return false}var p=this._get_move(),nms=[];if(p.o&&p.o.length){p.o.children("a").each(function(){nms.push($(this).text().replace(/^\s+/g,""))});return this._check_unique(nms,p.np.find("> ul > li").not(p.o))}return true}}})})(jQuery); \ No newline at end of file
diff --git a/www/js/jstree-1.0-rc2/themes/apple/bg.jpg b/www/js/jstree-1.0-rc2/themes/apple/bg.jpg
new file mode 100644
index 0000000..3aad05d
--- /dev/null
+++ b/www/js/jstree-1.0-rc2/themes/apple/bg.jpg
Binary files differ
diff --git a/www/js/jstree-1.0-rc2/themes/apple/d.png b/www/js/jstree-1.0-rc2/themes/apple/d.png
new file mode 100644
index 0000000..2463ba6
--- /dev/null
+++ b/www/js/jstree-1.0-rc2/themes/apple/d.png
Binary files differ
diff --git a/www/js/jstree-1.0-rc2/themes/apple/dot_for_ie.gif b/www/js/jstree-1.0-rc2/themes/apple/dot_for_ie.gif
new file mode 100644
index 0000000..c0cc5fd
--- /dev/null
+++ b/www/js/jstree-1.0-rc2/themes/apple/dot_for_ie.gif
Binary files differ
diff --git a/www/js/jstree-1.0-rc2/themes/apple/style.css b/www/js/jstree-1.0-rc2/themes/apple/style.css
new file mode 100644
index 0000000..8f1b3de
--- /dev/null
+++ b/www/js/jstree-1.0-rc2/themes/apple/style.css
@@ -0,0 +1,60 @@
+/*
+ * jsTree apple theme 1.0
+ * Supported features: dots/no-dots, icons/no-icons, focused, loading
+ * Supported plugins: ui (hovered, clicked), checkbox, contextmenu, search
+ */
+
+.jstree-apple > ul { background:url("bg.jpg") left top repeat; }
+.jstree-apple li,
+.jstree-apple ins { background-image:url("d.png"); background-repeat:no-repeat; background-color:transparent; }
+.jstree-apple li { background-position:-90px 0; background-repeat:repeat-y; }
+.jstree-apple li.jstree-last { background:transparent; }
+.jstree-apple .jstree-open > ins { background-position:-72px 0; }
+.jstree-apple .jstree-closed > ins { background-position:-54px 0; }
+.jstree-apple .jstree-leaf > ins { background-position:-36px 0; }
+
+.jstree-apple a { border-radius:4px; -moz-border-radius:4px; -webkit-border-radius:4px; text-shadow:1px 1px 1px white; }
+.jstree-apple .jstree-hovered { background:#e7f4f9; border:1px solid #d8f0fa; padding:0 3px 0 1px; text-shadow:1px 1px 1px silver; }
+.jstree-apple .jstree-clicked { background:#beebff; border:1px solid #99defd; padding:0 3px 0 1px; }
+.jstree-apple a .jstree-icon { background-position:-56px -20px; }
+.jstree-apple a.jstree-loading .jstree-icon { background:url("throbber.gif") center center no-repeat !important; }
+
+.jstree-apple.jstree-focused { background:white; }
+
+.jstree-apple .jstree-no-dots li,
+.jstree-apple .jstree-no-dots .jstree-leaf > ins { background:transparent; }
+.jstree-apple .jstree-no-dots .jstree-open > ins { background-position:-18px 0; }
+.jstree-apple .jstree-no-dots .jstree-closed > ins { background-position:0 0; }
+
+.jstree-apple .jstree-no-icons a .jstree-icon { display:none; }
+
+.jstree-apple .jstree-search { font-style:italic; }
+
+.jstree-apple .jstree-no-icons .jstree-checkbox { display:inline-block; }
+.jstree-apple .jstree-no-checkboxes .jstree-checkbox { display:none !important; }
+.jstree-apple .jstree-checked > a > .jstree-checkbox { background-position:-38px -19px; }
+.jstree-apple .jstree-unchecked > a > .jstree-checkbox { background-position:-2px -19px; }
+.jstree-apple .jstree-undetermined > a > .jstree-checkbox { background-position:-20px -19px; }
+.jstree-apple .jstree-checked > a > .checkbox:hover { background-position:-38px -37px; }
+.jstree-apple .jstree-unchecked > a > .jstree-checkbox:hover { background-position:-2px -37px; }
+.jstree-apple .jstree-undetermined > a > .jstree-checkbox:hover { background-position:-20px -37px; }
+
+#vakata-dragged.jstree-apple ins { background:transparent !important; }
+#vakata-dragged.jstree-apple .jstree-ok { background:url("d.png") -2px -53px no-repeat !important; }
+#vakata-dragged.jstree-apple .jstree-invalid { background:url("d.png") -18px -53px no-repeat !important; }
+#jstree-marker.jstree-apple { background:url("d.png") -41px -57px no-repeat !important; }
+
+.jstree-apple a.jstree-search { color:aqua; }
+
+#vakata-contextmenu.jstree-apple-context,
+#vakata-contextmenu.jstree-apple-context li ul { background:#f0f0f0; border:1px solid #979797; -moz-box-shadow: 1px 1px 2px #999; -webkit-box-shadow: 1px 1px 2px #999; box-shadow: 1px 1px 2px #999; }
+#vakata-contextmenu.jstree-apple-context li { }
+#vakata-contextmenu.jstree-apple-context a { color:black; }
+#vakata-contextmenu.jstree-apple-context a:hover,
+#vakata-contextmenu.jstree-apple-context .vakata-hover > a { padding:0 5px; background:#e8eff7; border:1px solid #aecff7; color:black; -moz-border-radius:2px; -webkit-border-radius:2px; border-radius:2px; }
+#vakata-contextmenu.jstree-apple-context li.jstree-contextmenu-disabled a,
+#vakata-contextmenu.jstree-apple-context li.jstree-contextmenu-disabled a:hover { color:silver; background:transparent; border:0; padding:1px 4px; }
+#vakata-contextmenu.jstree-apple-context li.vakata-separator { background:white; border-top:1px solid #e0e0e0; margin:0; }
+#vakata-contextmenu.jstree-apple-context li ul { margin-left:-4px; }
+
+/* TODO: IE6 support - the `>` selectors */ \ No newline at end of file
diff --git a/www/js/jstree-1.0-rc2/themes/apple/throbber.gif b/www/js/jstree-1.0-rc2/themes/apple/throbber.gif
new file mode 100644
index 0000000..5b33f7e
--- /dev/null
+++ b/www/js/jstree-1.0-rc2/themes/apple/throbber.gif
Binary files differ
diff --git a/www/js/jstree-1.0-rc2/themes/classic/d.png b/www/js/jstree-1.0-rc2/themes/classic/d.png
new file mode 100644
index 0000000..275daec
--- /dev/null
+++ b/www/js/jstree-1.0-rc2/themes/classic/d.png
Binary files differ
diff --git a/www/js/jstree-1.0-rc2/themes/classic/dot_for_ie.gif b/www/js/jstree-1.0-rc2/themes/classic/dot_for_ie.gif
new file mode 100644
index 0000000..c0cc5fd
--- /dev/null
+++ b/www/js/jstree-1.0-rc2/themes/classic/dot_for_ie.gif
Binary files differ
diff --git a/www/js/jstree-1.0-rc2/themes/classic/style.css b/www/js/jstree-1.0-rc2/themes/classic/style.css
new file mode 100644
index 0000000..bb15730
--- /dev/null
+++ b/www/js/jstree-1.0-rc2/themes/classic/style.css
@@ -0,0 +1,59 @@
+/*
+ * jsTree classic theme 1.0
+ * Supported features: dots/no-dots, icons/no-icons, focused, loading
+ * Supported plugins: ui (hovered, clicked), checkbox, contextmenu, search
+ */
+
+.jstree-classic li,
+.jstree-classic ins { background-image:url("d.png"); background-repeat:no-repeat; background-color:transparent; }
+.jstree-classic li { background-position:-90px 0; background-repeat:repeat-y; }
+.jstree-classic li.jstree-last { background:transparent; }
+.jstree-classic .jstree-open > ins { background-position:-72px 0; }
+.jstree-classic .jstree-closed > ins { background-position:-54px 0; }
+.jstree-classic .jstree-leaf > ins { background-position:-36px 0; }
+
+.jstree-classic .jstree-hovered { background:#e7f4f9; border:1px solid #e7f4f9; padding:0 2px 0 1px; }
+.jstree-classic .jstree-clicked { background:navy; border:1px solid navy; padding:0 2px 0 1px; color:white; }
+.jstree-classic a .jstree-icon { background-position:-56px -19px; }
+.jstree-classic .jstree-open > a .jstree-icon { background-position:-56px -36px; }
+.jstree-classic a.jstree-loading .jstree-icon { background:url("throbber.gif") center center no-repeat !important; }
+
+.jstree-classic.jstree-focused { background:white; }
+
+.jstree-classic .jstree-no-dots li,
+.jstree-classic .jstree-no-dots .jstree-leaf > ins { background:transparent; }
+.jstree-classic .jstree-no-dots .jstree-open > ins { background-position:-18px 0; }
+.jstree-classic .jstree-no-dots .jstree-closed > ins { background-position:0 0; }
+
+.jstree-classic .jstree-no-icons a .jstree-icon { display:none; }
+
+.jstree-classic .jstree-search { font-style:italic; }
+
+.jstree-classic .jstree-no-icons .jstree-checkbox { display:inline-block; }
+.jstree-classic .jstree-no-checkboxes .jstree-checkbox { display:none !important; }
+.jstree-classic .jstree-checked > a > .jstree-checkbox { background-position:-38px -19px; }
+.jstree-classic .jstree-unchecked > a > .jstree-checkbox { background-position:-2px -19px; }
+.jstree-classic .jstree-undetermined > a > .jstree-checkbox { background-position:-20px -19px; }
+.jstree-classic .jstree-checked > a > .jstree-checkbox:hover { background-position:-38px -37px; }
+.jstree-classic .jstree-unchecked > a > .jstree-checkbox:hover { background-position:-2px -37px; }
+.jstree-classic .jstree-undetermined > a > .jstree-checkbox:hover { background-position:-20px -37px; }
+
+#vakata-dragged.jstree-classic ins { background:transparent !important; }
+#vakata-dragged.jstree-classic .jstree-ok { background:url("d.png") -2px -53px no-repeat !important; }
+#vakata-dragged.jstree-classic .jstree-invalid { background:url("d.png") -18px -53px no-repeat !important; }
+#jstree-marker.jstree-classic { background:url("d.png") -41px -57px no-repeat !important; }
+
+.jstree-classic a.jstree-search { color:aqua; }
+
+#vakata-contextmenu.jstree-classic-context,
+#vakata-contextmenu.jstree-classic-context li ul { background:#f0f0f0; border:1px solid #979797; -moz-box-shadow: 1px 1px 2px #999; -webkit-box-shadow: 1px 1px 2px #999; box-shadow: 1px 1px 2px #999; }
+#vakata-contextmenu.jstree-classic-context li { }
+#vakata-contextmenu.jstree-classic-context a { color:black; }
+#vakata-contextmenu.jstree-classic-context a:hover,
+#vakata-contextmenu.jstree-classic-context .vakata-hover > a { padding:0 5px; background:#e8eff7; border:1px solid #aecff7; color:black; -moz-border-radius:2px; -webkit-border-radius:2px; border-radius:2px; }
+#vakata-contextmenu.jstree-classic-context li.jstree-contextmenu-disabled a,
+#vakata-contextmenu.jstree-classic-context li.jstree-contextmenu-disabled a:hover { color:silver; background:transparent; border:0; padding:1px 4px; }
+#vakata-contextmenu.jstree-classic-context li.vakata-separator { background:white; border-top:1px solid #e0e0e0; margin:0; }
+#vakata-contextmenu.jstree-classic-context li ul { margin-left:-4px; }
+
+/* TODO: IE6 support - the `>` selectors */ \ No newline at end of file
diff --git a/www/js/jstree-1.0-rc2/themes/classic/throbber.gif b/www/js/jstree-1.0-rc2/themes/classic/throbber.gif
new file mode 100644
index 0000000..5b33f7e
--- /dev/null
+++ b/www/js/jstree-1.0-rc2/themes/classic/throbber.gif
Binary files differ
diff --git a/www/js/jstree-1.0-rc2/themes/default-rtl/d.gif b/www/js/jstree-1.0-rc2/themes/default-rtl/d.gif
new file mode 100644
index 0000000..d85aba0
--- /dev/null
+++ b/www/js/jstree-1.0-rc2/themes/default-rtl/d.gif
Binary files differ
diff --git a/www/js/jstree-1.0-rc2/themes/default-rtl/d.png b/www/js/jstree-1.0-rc2/themes/default-rtl/d.png
new file mode 100644
index 0000000..5179cf6
--- /dev/null
+++ b/www/js/jstree-1.0-rc2/themes/default-rtl/d.png
Binary files differ
diff --git a/www/js/jstree-1.0-rc2/themes/default-rtl/dots.gif b/www/js/jstree-1.0-rc2/themes/default-rtl/dots.gif
new file mode 100644
index 0000000..0043364
--- /dev/null
+++ b/www/js/jstree-1.0-rc2/themes/default-rtl/dots.gif
Binary files differ
diff --git a/www/js/jstree-1.0-rc2/themes/default-rtl/style.css b/www/js/jstree-1.0-rc2/themes/default-rtl/style.css
new file mode 100644
index 0000000..3ad0727
--- /dev/null
+++ b/www/js/jstree-1.0-rc2/themes/default-rtl/style.css
@@ -0,0 +1,83 @@
+/*
+ * jsTree default-rtl theme 1.0
+ * Supported features: dots/no-dots, icons/no-icons, focused, loading
+ * Supported plugins: ui (hovered, clicked), checkbox, contextmenu, search
+ */
+
+.jstree-default-rtl li,
+.jstree-default-rtl ins { background-image:url("d.png"); background-repeat:no-repeat; background-color:transparent; }
+.jstree-default-rtl li { background-position:-90px 0; background-repeat:repeat-y; }
+.jstree-default-rtl li.jstree-last { background:transparent; }
+.jstree-default-rtl .jstree-open > ins { background-position:-72px 0; }
+.jstree-default-rtl .jstree-closed > ins { background-position:-54px 0; }
+.jstree-default-rtl .jstree-leaf > ins { background-position:-36px 0; }
+
+.jstree-default-rtl .jstree-hovered { background:#e7f4f9; border:1px solid #d8f0fa; padding:0 2px 0 1px; }
+.jstree-default-rtl .jstree-clicked { background:#beebff; border:1px solid #99defd; padding:0 2px 0 1px; }
+.jstree-default-rtl a .jstree-icon { background-position:-56px -19px; }
+.jstree-default-rtl a.jstree-loading .jstree-icon { background:url("throbber.gif") center center no-repeat !important; }
+
+.jstree-default-rtl.jstree-focused { background:#ffffee; }
+
+.jstree-default-rtl .jstree-no-dots li,
+.jstree-default-rtl .jstree-no-dots .jstree-leaf > ins { background:transparent; }
+.jstree-default-rtl .jstree-no-dots .jstree-open > ins { background-position:-18px 0; }
+.jstree-default-rtl .jstree-no-dots .jstree-closed > ins { background-position:0 0; }
+
+.jstree-default-rtl .jstree-no-icons a .jstree-icon { display:none; }
+
+.jstree-default-rtl .jstree-search { font-style:italic; }
+
+.jstree-default-rtl .jstree-no-icons .jstree-checkbox { display:inline-block; }
+.jstree-default-rtl .jstree-no-checkboxes .jstree-checkbox { display:none !important; }
+.jstree-default-rtl .jstree-checked > a > .jstree-checkbox { background-position:-38px -19px; }
+.jstree-default-rtl .jstree-unchecked > a > .jstree-checkbox { background-position:-2px -19px; }
+.jstree-default-rtl .jstree-undetermined > a > .jstree-checkbox { background-position:-20px -19px; }
+.jstree-default-rtl .jstree-checked > a > .jstree-checkbox:hover { background-position:-38px -37px; }
+.jstree-default-rtl .jstree-unchecked > a > .jstree-checkbox:hover { background-position:-2px -37px; }
+.jstree-default-rtl .jstree-undetermined > a > .jstree-checkbox:hover { background-position:-20px -37px; }
+
+#vakata-dragged.jstree-default-rtl ins { background:transparent !important; }
+#vakata-dragged.jstree-default-rtl .jstree-ok { background:url("d.png") -2px -53px no-repeat !important; }
+#vakata-dragged.jstree-default-rtl .jstree-invalid { background:url("d.png") -18px -53px no-repeat !important; }
+#jstree-marker.jstree-default-rtl { background:url("d.png") -41px -57px no-repeat !important; }
+
+.jstree-default-rtl a.jstree-search { color:aqua; }
+
+#vakata-contextmenu.jstree-default-rtl-context,
+#vakata-contextmenu.jstree-default-rtl-context li ul { background:#f0f0f0; border:1px solid #979797; -moz-box-shadow: 1px 1px 2px #999; -webkit-box-shadow: 1px 1px 2px #999; box-shadow: 1px 1px 2px #999; }
+#vakata-contextmenu.jstree-default-rtl-context li { }
+#vakata-contextmenu.jstree-default-rtl-context a { color:black; }
+#vakata-contextmenu.jstree-default-rtl-context a:hover,
+#vakata-contextmenu.jstree-default-rtl-context .vakata-hover > a { padding:0 5px; background:#e8eff7; border:1px solid #aecff7; color:black; -moz-border-radius:2px; -webkit-border-radius:2px; border-radius:2px; }
+#vakata-contextmenu.jstree-default-rtl-context li.jstree-contextmenu-disabled a,
+#vakata-contextmenu.jstree-default-rtl-context li.jstree-contextmenu-disabled a:hover { color:silver; background:transparent; border:0; padding:1px 4px; }
+#vakata-contextmenu.jstree-default-rtl-context li.vakata-separator { background:white; border-top:1px solid #e0e0e0; margin:0; }
+#vakata-contextmenu.jstree-default-rtl-context li ul { margin-left:-4px; }
+
+/* IE6 BEGIN */
+.jstree-default-rtl li,
+.jstree-default-rtl ins,
+#vakata-dragged.jstree-default-rtl .jstree-invalid,
+#vakata-dragged.jstree-default-rtl .jstree-ok,
+#jstree-marker.jstree-default-rtl { _background-image:url("d.gif"); }
+.jstree-default-rtl .jstree-open ins { _background-position:-72px 0; }
+.jstree-default-rtl .jstree-closed ins { _background-position:-54px 0; }
+.jstree-default-rtl .jstree-leaf ins { _background-position:-36px 0; }
+.jstree-default-rtl a ins.jstree-icon { _background-position:-56px -19px; }
+#vakata-contextmenu.jstree-default-rtl-context ins { _display:none; }
+#vakata-contextmenu.jstree-default-rtl-context li { _zoom:1; }
+.jstree-default-rtl .jstree-undetermined a .jstree-checkbox { _background-position:-18px -19px; }
+.jstree-default-rtl .jstree-checked a .jstree-checkbox { _background-position:-36px -19px; }
+.jstree-default-rtl .jstree-unchecked a .jstree-checkbox { _background-position:0px -19px; }
+/* IE6 END */
+
+/* RTL part */
+.jstree-default-rtl .jstree-hovered, .jstree-default-rtl .jstree-clicked { padding:0 1px 0 2px; }
+.jstree-default-rtl li { background-image:url("dots.gif"); background-position: 100% 0px; }
+.jstree-default-rtl .jstree-checked > a > .jstree-checkbox { background-position:-36px -19px; margin-left:2px; }
+.jstree-default-rtl .jstree-unchecked > a > .jstree-checkbox { background-position:0px -19px; margin-left:2px; }
+.jstree-default-rtl .jstree-undetermined > a > .jstree-checkbox { background-position:-18px -19px; margin-left:2px; }
+.jstree-default-rtl .jstree-checked > a > .jstree-checkbox:hover { background-position:-36px -37px; }
+.jstree-default-rtl .jstree-unchecked > a > .jstree-checkbox:hover { background-position:0px -37px; }
+.jstree-default-rtl .jstree-undetermined > a > .jstree-checkbox:hover { background-position:-18px -37px; } \ No newline at end of file
diff --git a/www/js/jstree-1.0-rc2/themes/default-rtl/throbber.gif b/www/js/jstree-1.0-rc2/themes/default-rtl/throbber.gif
new file mode 100644
index 0000000..5b33f7e
--- /dev/null
+++ b/www/js/jstree-1.0-rc2/themes/default-rtl/throbber.gif
Binary files differ
diff --git a/www/js/jstree-1.0-rc2/themes/default/d.gif b/www/js/jstree-1.0-rc2/themes/default/d.gif
new file mode 100644
index 0000000..0e958d3
--- /dev/null
+++ b/www/js/jstree-1.0-rc2/themes/default/d.gif
Binary files differ
diff --git a/www/js/jstree-1.0-rc2/themes/default/d.png b/www/js/jstree-1.0-rc2/themes/default/d.png
new file mode 100644
index 0000000..8540175
--- /dev/null
+++ b/www/js/jstree-1.0-rc2/themes/default/d.png
Binary files differ
diff --git a/www/js/jstree-1.0-rc2/themes/default/style.css b/www/js/jstree-1.0-rc2/themes/default/style.css
new file mode 100644
index 0000000..01a0889
--- /dev/null
+++ b/www/js/jstree-1.0-rc2/themes/default/style.css
@@ -0,0 +1,73 @@
+/*
+ * jsTree default theme 1.0
+ * Supported features: dots/no-dots, icons/no-icons, focused, loading
+ * Supported plugins: ui (hovered, clicked), checkbox, contextmenu, search
+ */
+
+.jstree-default li,
+.jstree-default ins { background-image:url("d.png"); background-repeat:no-repeat; background-color:transparent; }
+.jstree-default li { background-position:-90px 0; background-repeat:repeat-y; }
+.jstree-default li.jstree-last { background:transparent; }
+.jstree-default .jstree-open > ins { background-position:-72px 0; }
+.jstree-default .jstree-closed > ins { background-position:-54px 0; }
+.jstree-default .jstree-leaf > ins { background-position:-36px 0; }
+
+.jstree-default .jstree-hovered { background:#e7f4f9; border:1px solid #d8f0fa; padding:0 2px 0 1px; }
+.jstree-default .jstree-clicked { background:#beebff; border:1px solid #99defd; padding:0 2px 0 1px; }
+.jstree-default a .jstree-icon { background-position:-56px -19px; }
+.jstree-default a.jstree-loading .jstree-icon { background:url("throbber.gif") center center no-repeat !important; }
+
+.jstree-default.jstree-focused { background:#ffffee; }
+
+.jstree-default .jstree-no-dots li,
+.jstree-default .jstree-no-dots .jstree-leaf > ins { background:transparent; }
+.jstree-default .jstree-no-dots .jstree-open > ins { background-position:-18px 0; }
+.jstree-default .jstree-no-dots .jstree-closed > ins { background-position:0 0; }
+
+.jstree-default .jstree-no-icons a .jstree-icon { display:none; }
+
+.jstree-default .jstree-search { font-style:italic; }
+
+.jstree-default .jstree-no-icons .jstree-checkbox { display:inline-block; }
+.jstree-default .jstree-no-checkboxes .jstree-checkbox { display:none !important; }
+.jstree-default .jstree-checked > a > .jstree-checkbox { background-position:-38px -19px; }
+.jstree-default .jstree-unchecked > a > .jstree-checkbox { background-position:-2px -19px; }
+.jstree-default .jstree-undetermined > a > .jstree-checkbox { background-position:-20px -19px; }
+.jstree-default .jstree-checked > a > .jstree-checkbox:hover { background-position:-38px -37px; }
+.jstree-default .jstree-unchecked > a > .jstree-checkbox:hover { background-position:-2px -37px; }
+.jstree-default .jstree-undetermined > a > .jstree-checkbox:hover { background-position:-20px -37px; }
+
+#vakata-dragged.jstree-default ins { background:transparent !important; }
+#vakata-dragged.jstree-default .jstree-ok { background:url("d.png") -2px -53px no-repeat !important; }
+#vakata-dragged.jstree-default .jstree-invalid { background:url("d.png") -18px -53px no-repeat !important; }
+#jstree-marker.jstree-default { background:url("d.png") -41px -57px no-repeat !important; }
+
+.jstree-default a.jstree-search { color:aqua; }
+
+#vakata-contextmenu.jstree-default-context,
+#vakata-contextmenu.jstree-default-context li ul { background:#f0f0f0; border:1px solid #979797; -moz-box-shadow: 1px 1px 2px #999; -webkit-box-shadow: 1px 1px 2px #999; box-shadow: 1px 1px 2px #999; }
+#vakata-contextmenu.jstree-default-context li { }
+#vakata-contextmenu.jstree-default-context a { color:black; }
+#vakata-contextmenu.jstree-default-context a:hover,
+#vakata-contextmenu.jstree-default-context .vakata-hover > a { padding:0 5px; background:#e8eff7; border:1px solid #aecff7; color:black; -moz-border-radius:2px; -webkit-border-radius:2px; border-radius:2px; }
+#vakata-contextmenu.jstree-default-context li.jstree-contextmenu-disabled a,
+#vakata-contextmenu.jstree-default-context li.jstree-contextmenu-disabled a:hover { color:silver; background:transparent; border:0; padding:1px 4px; }
+#vakata-contextmenu.jstree-default-context li.vakata-separator { background:white; border-top:1px solid #e0e0e0; margin:0; }
+#vakata-contextmenu.jstree-default-context li ul { margin-left:-4px; }
+
+/* IE6 BEGIN */
+.jstree-default li,
+.jstree-default ins,
+#vakata-dragged.jstree-default .jstree-invalid,
+#vakata-dragged.jstree-default .jstree-ok,
+#jstree-marker.jstree-default { _background-image:url("d.gif"); }
+.jstree-default .jstree-open ins { _background-position:-72px 0; }
+.jstree-default .jstree-closed ins { _background-position:-54px 0; }
+.jstree-default .jstree-leaf ins { _background-position:-36px 0; }
+.jstree-default a ins.jstree-icon { _background-position:-56px -19px; }
+#vakata-contextmenu.jstree-default-context ins { _display:none; }
+#vakata-contextmenu.jstree-default-context li { _zoom:1; }
+.jstree-default .jstree-undetermined a .jstree-checkbox { _background-position:-20px -19px; }
+.jstree-default .jstree-checked a .jstree-checkbox { _background-position:-38px -19px; }
+.jstree-default .jstree-unchecked a .jstree-checkbox { _background-position:-2px -19px; }
+/* IE6 END */ \ No newline at end of file
diff --git a/www/js/jstree-1.0-rc2/themes/default/throbber.gif b/www/js/jstree-1.0-rc2/themes/default/throbber.gif
new file mode 100644
index 0000000..5b33f7e
--- /dev/null
+++ b/www/js/jstree-1.0-rc2/themes/default/throbber.gif
Binary files differ
diff --git a/www/jsScuttle.php b/www/jsScuttle.php
index f37da78..c166755 100644
--- a/www/jsScuttle.php
+++ b/www/jsScuttle.php
@@ -155,7 +155,10 @@ function processVotingResult() {
var bmnode = document.getElementById('bmv-'+bookmark);
bmnode.parentNode.replaceChild(
- response.getElementsByTagName('html')[0].firstChild,
+ xmlhttp.responseXML.importNode(
+ response.getElementsByTagName('html')[0].firstChild,
+ true
+ ),
bmnode
);
}
diff --git a/www/rss.php b/www/rss.php
index 6dcfb4c..298d9ba 100644
--- a/www/rss.php
+++ b/www/rss.php
@@ -116,7 +116,7 @@ foreach ($bookmarks_tmp as $key => $row) {
'title' => $row['bTitle'],
'link' => $_link,
'description' => $row['bDescription'],
- 'creator' => $row['username'],
+ 'creator' => SemanticScuttle_Model_UserArray::getName($row),
'pubdate' => $_pubdate,
'tags' => $row['tags']
);
diff --git a/www/scuttle.css b/www/scuttle.css
index c23e297..480b7f4 100644
--- a/www/scuttle.css
+++ b/www/scuttle.css
@@ -376,6 +376,7 @@ div#sidebar table td {
padding-bottom: 0.25em;
padding-right: 0.5em;
}
+/*
div#sidebar ul {
list-style-type: none;
margin: 0;
@@ -383,7 +384,7 @@ div#sidebar ul {
}
div#sidebar ul li {
margin: 0.5em 0;
-}
+}*/
div#related {
padding: 0.5em;
@@ -643,11 +644,13 @@ a.bookmarklet {
background-color: #AAFAEE;
}
-/* DOJO Style */
+/* tree styles */
+#related-content.jstree-default.jstree-focused {
+ background: none !important;
+}
+
-/* DOJO Style */
-.scuttletheme .dijitInputField input,.scuttletheme .dijitTextBox,.scuttletheme .dijitComboBox,.scuttletheme .dijitSpinner
- {
- width: 100%;
- margin: 0 0 0 0;
+/* add/edit bookmark */
+.ui-autocomplete {
+ width: 458px;
}
diff --git a/www/tag2tagadd.php b/www/tag2tagadd.php
index cf8a639..d660451 100644
--- a/www/tag2tagadd.php
+++ b/www/tag2tagadd.php
@@ -40,7 +40,11 @@ if(!$userservice->isLoggedOn()) {
}
/* Managing path info */
-list ($url, $tag1) = explode('/', $_SERVER['PATH_INFO']);
+if (isset($_SERVER['PATH_INFO'])) {
+ list ($url, $tag1) = explode('/', $_SERVER['PATH_INFO']);
+} else {
+ $url = $tag1 = null;
+}
if (POST_CONFIRM != '') {
$tag1 = POST_TAG1;
diff --git a/www/www-header.php b/www/www-header.php
index 0688b71..cc5a5ae 100644
--- a/www/www-header.php
+++ b/www/www-header.php
@@ -15,5 +15,11 @@
* @license GPL http://www.gnu.org/licenses/gpl.html
* @link http://sourceforge.net/projects/semanticscuttle
*/
-require_once dirname(__FILE__) . '/../src/SemanticScuttle/header.php';
+if ('@data_dir@' == '@' . 'data_dir@') {
+ //non pear-install
+ require_once dirname(__FILE__) . '/../src/SemanticScuttle/header.php';
+} else {
+ //pear installation; files are in include path
+ require_once 'SemanticScuttle/header.php';
+}
?> \ No newline at end of file