Merge branch 'master' into 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
This commit is contained in:
Christian Weiske 2011-04-06 19:13:19 +02:00
commit 7379805565
147 changed files with 18747 additions and 2296 deletions

2
.gitignore vendored
View File

@ -1,2 +1,4 @@
dist/ dist/
build.properties build.properties
package.xml
semanticscuttle-dump.sql

View File

@ -1 +1,2 @@
sfuser=FIXME sfuser=FIXME
websitedir=FIXME

227
build.xml
View File

@ -7,15 +7,31 @@
tagging a release, running unit tests etc. tagging a release, running unit tests etc.
--> -->
<property file="build.properties" /> <property file="build.properties" />
<property file="html.properties" />
<property name="version-m" value="0.97" /> <property name="version-m" value="0.97" />
<property name="version" value="0.97.0" /> <property name="version" value="0.97.0" />
<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="zipfile" value="${phing.project.name}-${version}.zip" />
<property name="pkgfile" value="${phing.project.name}-${version}.tgz" />
<property name="distfile" value="dist/${zipfile}" /> <property name="distfile" value="dist/${zipfile}" />
<property name="distpkgfile" value="dist/pear/${pkgfile}" />
<property name="sfproject" value="SemanticScuttle" /> <property name="sfproject" value="SemanticScuttle" />
<property name="sffilepath" value="s/se/semanticscuttle/" /> <property name="sffilepath" value="s/se/semanticscuttle/" />
<property name="svnpath" value="https://semanticscuttle.svn.sourceforge.net/svnroot/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" <target name="zip" depends="check"
description="Create zip file for release" 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" description="Release the version on sourceforge"
> >
<!-- meta-target --> <!-- meta-target -->
@ -80,12 +240,69 @@
</target> </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 <exec
command="svn cp ${svnpath}trunk ${svnpath}/tags/${version} -m 'tag version ${version}'" command="rsync --include-from=.rsync-include-files --delete -avP -e ssh ${sfuser},${sfproject}@web.sourceforge.net:htdocs/ ."
escape="false" checkreturn="true" dir="${websitedir}"
escape="false" checkreturn="false"
passthru="true"
/>
<exec
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> </target>

View File

@ -138,7 +138,7 @@ $dbtype = 'mysql4';
* *
* @var string * @var string
*/ */
$dbhost = 'localhost'; $dbhost = '127.0.0.1';
/** /**
* Database port. * Database port.
@ -302,7 +302,7 @@ $index_sidebar_blocks = array(
* @var string * @var string
* @link http://php.net/date * @link http://php.net/date
*/ */
$shortdate = 'd-m-Y'; $shortdate = 'Y-m-d';
/** /**
* Format of long dates. * Format of long dates.
@ -710,4 +710,12 @@ $authEmailSuffix = null;
*/ */
$unittestUrl = null; $unittestUrl = null;
/**
* Allow "unittestMode=1" in URLs.
* Should only be enabled on development systems
*
* @var boolean
*/
$allowUnittestMode = false;
?> ?>

View File

@ -88,7 +88,7 @@ $dbname = 'scuttle';
* *
* @var string * @var string
*/ */
$dbhost = 'localhost'; $dbhost = '127.0.0.1';
/*************************************************** /***************************************************

View File

@ -604,7 +604,7 @@ msgid ""
"file to your computer" "file to your computer"
msgstr "" msgstr ""
"Speichern Sie die resultierende <abbr title=\"Extensible Markup Language" "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 #: data/templates/importDelicious.tpl.php:35
msgid "" msgid ""

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -8,7 +8,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: PACKAGE VERSION\n" "Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \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" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n" "Language-Team: LANGUAGE <LL@li.org>\n"
@ -17,50 +17,50 @@ msgstr ""
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\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." msgid "message_die() was called multiple times."
msgstr "" msgstr ""
#: src/SemanticScuttle/functions.php:175 #: src/SemanticScuttle/functions.php:201
msgid "SQL Error" msgid "SQL Error"
msgstr "" msgstr ""
#: src/SemanticScuttle/functions.php:181 #: src/SemanticScuttle/functions.php:207
msgid "Line" msgid "Line"
msgstr "" msgstr ""
#: src/SemanticScuttle/functions.php:181 #: src/SemanticScuttle/functions.php:207
#: data/templates/importDelicious.tpl.php:8 #: data/templates/importDelicious.tpl.php:8
#: data/templates/importNetscape.tpl.php:9 #: data/templates/importNetscape.tpl.php:9
#: data/templates/importStructure.tpl.php:10 #: data/templates/importStructure.tpl.php:10
msgid "File" msgid "File"
msgstr "" msgstr ""
#: src/SemanticScuttle/functions.php:189 #: src/SemanticScuttle/functions.php:215
msgid "Information" msgid "Information"
msgstr "" msgstr ""
#: src/SemanticScuttle/functions.php:194 #: src/SemanticScuttle/functions.php:220
msgid "Critical Information" msgid "Critical Information"
msgstr "" msgstr ""
#: src/SemanticScuttle/functions.php:199 #: src/SemanticScuttle/functions.php:225
msgid "An error occured" msgid "An error occured"
msgstr "" msgstr ""
#: src/SemanticScuttle/functions.php:202 #: src/SemanticScuttle/functions.php:228
msgid "General Error" msgid "General Error"
msgstr "" msgstr ""
#: src/SemanticScuttle/functions.php:210 #: src/SemanticScuttle/functions.php:236
msgid "An critical error occured" msgid "An critical error occured"
msgstr "" msgstr ""
#: src/SemanticScuttle/functions.php:213 #: src/SemanticScuttle/functions.php:239
msgid "Critical Error" msgid "Critical Error"
msgstr "" msgstr ""
#: src/SemanticScuttle/functions.php:222 #: src/SemanticScuttle/functions.php:248
msgid "DEBUG MODE" msgid "DEBUG MODE"
msgstr "" msgstr ""
@ -150,7 +150,7 @@ msgstr ""
msgid "Are you sure?" msgid "Are you sure?"
msgstr "" 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" msgid "Delete"
msgstr "" msgstr ""
@ -169,12 +169,12 @@ msgid ""
msgstr "" msgstr ""
#: data/templates/bookmarkcommondescriptionedit.tpl.php:18 #: 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" msgid "Title"
msgstr "" msgstr ""
#: data/templates/bookmarkcommondescriptionedit.tpl.php:23 #: 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/editprofile.tpl.php:47 data/templates/profile.tpl.php:33
#: data/templates/tagcommondescriptionedit.tpl.php:13 #: data/templates/tagcommondescriptionedit.tpl.php:13
#: data/templates/tagedit.tpl.php:12 #: data/templates/tagedit.tpl.php:12
@ -193,8 +193,8 @@ msgid "Update"
msgstr "" msgstr ""
#: data/templates/bookmarkcommondescriptionedit.tpl.php:43 #: data/templates/bookmarkcommondescriptionedit.tpl.php:43
#: data/templates/editbookmark.tpl.php:98 data/templates/tag2tagadd.tpl.php:24 #: data/templates/editbookmark.tpl.php:103
#: data/templates/tag2tagedit.tpl.php:38 #: data/templates/tag2tagadd.tpl.php:24 data/templates/tag2tagedit.tpl.php:38
#: data/templates/tagcommondescriptionedit.tpl.php:33 #: 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" msgid "Cancel"
@ -273,61 +273,61 @@ msgstr ""
msgid "Page %d of %d" msgid "Page %d of %d"
msgstr "" msgstr ""
#: data/templates/bookmarks.tpl.php:245 #: data/templates/bookmarks.tpl.php:261
msgid "Tags:" msgid "Tags:"
msgstr "" msgstr ""
#: data/templates/bookmarks.tpl.php:251 #: data/templates/bookmarks.tpl.php:267
msgid "Edit" msgid "Edit"
msgstr "" msgstr ""
#: data/templates/bookmarks.tpl.php:255 #: data/templates/bookmarks.tpl.php:271
msgid "Last update" msgid "Last update"
msgstr "" msgstr ""
#: data/templates/bookmarks.tpl.php:258 #: data/templates/bookmarks.tpl.php:274
msgid "by" msgid "by"
msgstr "" msgstr ""
#: data/templates/bookmarks.tpl.php:260 #: data/templates/bookmarks.tpl.php:276
msgid "you" msgid "you"
msgstr "" msgstr ""
#: data/templates/bookmarks.tpl.php:274 #: data/templates/bookmarks.tpl.php:290
#, php-format #, php-format
msgid " and %s1 other%s" msgid " and %s1 other%s"
msgstr "" msgstr ""
#: data/templates/bookmarks.tpl.php:277 #: data/templates/bookmarks.tpl.php:293
#, php-format #, php-format
msgid " and %2$s%1$s others%3$s" msgid " and %2$s%1$s others%3$s"
msgstr "" msgstr ""
#: data/templates/bookmarks.tpl.php:288 #: data/templates/bookmarks.tpl.php:304
msgid "Copy this bookmark to YOUR bookmarks." msgid "Copy this bookmark to YOUR bookmarks."
msgstr "" msgstr ""
#: data/templates/bookmarks.tpl.php:289 #: data/templates/bookmarks.tpl.php:305
msgid "Copy" msgid "Copy"
msgstr "" msgstr ""
#: data/templates/bookmarks.tpl.php:309 #: data/templates/bookmarks.tpl.php:325
msgid "This bookmark is certified by an admin user." msgid "This bookmark is certified by an admin user."
msgstr "" msgstr ""
#: data/templates/bookmarks.tpl.php:351 #: data/templates/bookmarks.tpl.php:371
msgid "Private Note on this bookmark" msgid "Private Note on this bookmark"
msgstr "" msgstr ""
#: data/templates/bookmarks.tpl.php:363 #: data/templates/bookmarks.tpl.php:383
msgid "Come back to the top of this page." msgid "Come back to the top of this page."
msgstr "" msgstr ""
#: data/templates/bookmarks.tpl.php:363 #: data/templates/bookmarks.tpl.php:383
msgid "Top of the page" msgid "Top of the page"
msgstr "" msgstr ""
#: data/templates/bookmarks.tpl.php:369 #: data/templates/bookmarks.tpl.php:389
msgid "No bookmarks available" msgid "No bookmarks available"
msgstr "" msgstr ""
@ -362,133 +362,133 @@ msgstr ""
msgid "Popular Tags From All Users" msgid "Popular Tags From All Users"
msgstr "" msgstr ""
#: data/templates/editbookmark.tpl.php:33 #: data/templates/editbookmark.tpl.php:38
msgid "Address" msgid "Address"
msgstr "" msgstr ""
#: data/templates/editbookmark.tpl.php:35
#: data/templates/editbookmark.tpl.php:40 #: 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/editprofile.tpl.php:31 data/templates/tagrename.tpl.php:14
#: data/templates/tagrename.tpl.php:19 #: data/templates/tagrename.tpl.php:19
msgid "Required" msgid "Required"
msgstr "" msgstr ""
#: data/templates/editbookmark.tpl.php:45 #: data/templates/editbookmark.tpl.php:50
msgid "Add Note" msgid "Add Note"
msgstr "" msgstr ""
#: data/templates/editbookmark.tpl.php:48 #: data/templates/editbookmark.tpl.php:53
msgid "" msgid ""
"You can use anchors to delimite attributes. for example: [publisher]blah[/" "You can use anchors to delimite attributes. for example: [publisher]blah[/"
"publisher] " "publisher] "
msgstr "" msgstr ""
#: data/templates/editbookmark.tpl.php:51 #: data/templates/editbookmark.tpl.php:56
msgid "Suggested anchors: " msgid "Suggested anchors: "
msgstr "" msgstr ""
#: data/templates/editbookmark.tpl.php:63 #: data/templates/editbookmark.tpl.php:68
msgid "Private Note" msgid "Private Note"
msgstr "" msgstr ""
#: data/templates/editbookmark.tpl.php:65 #: data/templates/editbookmark.tpl.php:70
msgid "Just visible by you and your contacts." msgid "Just visible by you and your contacts."
msgstr "" 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 #: www/tags.php:45 www/tags.php:67
msgid "Tags" msgid "Tags"
msgstr "" msgstr ""
#: data/templates/editbookmark.tpl.php:73 #: data/templates/editbookmark.tpl.php:78
msgid "Comma-separated" msgid "Comma-separated"
msgstr "" 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 "" msgid ""
"Note: use \">\" to include one tag in another. e.g.: europe>france>paris" "Note: use \">\" to include one tag in another. e.g.: europe>france>paris"
msgstr "" 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" msgid "Note: use \"=\" to make synonym two tags. e.g.: france=frenchcountry"
msgstr "" msgstr ""
#: data/templates/editbookmark.tpl.php:84 #: data/templates/editbookmark.tpl.php:89
#: data/templates/importDelicious.tpl.php:15 #: data/templates/importDelicious.tpl.php:15
#: data/templates/importNetscape.tpl.php:16 #: data/templates/importNetscape.tpl.php:16
msgid "Privacy" msgid "Privacy"
msgstr "" msgstr ""
#: data/templates/editbookmark.tpl.php:87 #: data/templates/editbookmark.tpl.php:92
#: data/templates/importDelicious.tpl.php:18 #: data/templates/importDelicious.tpl.php:18
#: data/templates/importNetscape.tpl.php:19 #: data/templates/importNetscape.tpl.php:19
msgid "Public" msgid "Public"
msgstr "" msgstr ""
#: data/templates/editbookmark.tpl.php:88 #: data/templates/editbookmark.tpl.php:93
msgid "Shared with Watch List" msgid "Shared with Watch List"
msgstr "" msgstr ""
#: data/templates/editbookmark.tpl.php:89 #: data/templates/editbookmark.tpl.php:94
#: data/templates/importDelicious.tpl.php:20 #: data/templates/importDelicious.tpl.php:20
#: data/templates/importNetscape.tpl.php:21 #: data/templates/importNetscape.tpl.php:21
msgid "Private" msgid "Private"
msgstr "" msgstr ""
#: data/templates/editbookmark.tpl.php:102 #: data/templates/editbookmark.tpl.php:107
msgid "Delete Bookmark" msgid "Delete Bookmark"
msgstr "" msgstr ""
#: data/templates/editbookmark.tpl.php:107 #: data/templates/editbookmark.tpl.php:112
msgid "edit common description" msgid "edit common description"
msgstr "" msgstr ""
#: data/templates/editbookmark.tpl.php:134 #: data/templates/editbookmark.tpl.php:139
msgid "Bookmarklet" msgid "Bookmarklet"
msgstr "" msgstr ""
#: data/templates/editbookmark.tpl.php:140 #: data/templates/editbookmark.tpl.php:145
#, php-format #, php-format
msgid "" msgid ""
"Click one of the following bookmarklets to add a button you can click " "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" "whenever you want to add the page you are on to %s"
msgstr "" msgstr ""
#: data/templates/editbookmark.tpl.php:144 #: data/templates/editbookmark.tpl.php:149
#, php-format #, php-format
msgid "" msgid ""
"Drag one of the following bookmarklets to your browser's bookmarks and click " "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" "it whenever you want to add the page you are on to %s"
msgstr "" msgstr ""
#: data/templates/editbookmark.tpl.php:157
#: data/templates/editbookmark.tpl.php:162 #: data/templates/editbookmark.tpl.php:162
#: data/templates/editbookmark.tpl.php:167
#, php-format #, php-format
msgid "Post to %s" msgid "Post to %s"
msgstr "" msgstr ""
#: data/templates/editbookmark.tpl.php:158
#: data/templates/editbookmark.tpl.php:163 #: data/templates/editbookmark.tpl.php:163
#: data/templates/editbookmark.tpl.php:168
#, php-format #, php-format
msgid "Post to %s (Pop-up)" msgid "Post to %s (Pop-up)"
msgstr "" msgstr ""
#: data/templates/editbookmark.tpl.php:168 #: data/templates/editbookmark.tpl.php:173
#: data/templates/importDelicious.tpl.php:26 #: data/templates/importDelicious.tpl.php:26
#: data/templates/importNetscape.tpl.php:27 #: data/templates/importNetscape.tpl.php:27
#: data/templates/importStructure.tpl.php:16 #: data/templates/importStructure.tpl.php:16
msgid "Import" msgid "Import"
msgstr "" msgstr ""
#: data/templates/editbookmark.tpl.php:170 #: data/templates/editbookmark.tpl.php:175
msgid "Import bookmarks from bookmark file" msgid "Import bookmarks from bookmark file"
msgstr "" msgstr ""
#: data/templates/editbookmark.tpl.php:170 #: data/templates/editbookmark.tpl.php:175
msgid "Internet Explorer, Mozilla Firefox and Netscape" msgid "Internet Explorer, Mozilla Firefox and Netscape"
msgstr "" msgstr ""
#: data/templates/editbookmark.tpl.php:171 #: data/templates/editbookmark.tpl.php:176
msgid "Import bookmarks from del.icio.us" msgid "Import bookmarks from del.icio.us"
msgstr "" msgstr ""
@ -841,7 +841,7 @@ msgid "Edit Tag Description"
msgstr "" msgstr ""
#: data/templates/sidebar.block.tagactions.php:26 #: data/templates/sidebar.block.tagactions.php:26
#: www/tagcommondescriptionedit.php:64 #: www/tagcommondescriptionedit.php:76
msgid "Edit Tag Common Description" msgid "Edit Tag Common Description"
msgstr "" msgstr ""
@ -1028,12 +1028,12 @@ msgstr ""
msgid "Failed to delete bookmark" msgid "Failed to delete bookmark"
msgstr "" msgstr ""
#: www/alltags.php:49 #: www/alltags.php:50
msgid "All Tags" msgid "All Tags"
msgstr "" msgstr ""
#: www/alltags.php:55 www/bookmarks.php:96 www/populartags.php:52 #: www/alltags.php:56 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/profile.php:51 www/rss.php:76 www/search.php:109 www/watch.php:45
#: www/watchlist.php:61 #: www/watchlist.php:61
#, php-format #, php-format
msgid "User with username %s was not found" msgid "User with username %s was not found"
@ -1041,7 +1041,7 @@ msgstr ""
#: www/bookmarkcommondescriptionedit.php:51 www/tag2tagadd.php:37 #: www/bookmarkcommondescriptionedit.php:51 www/tag2tagadd.php:37
#: www/tag2tagdelete.php:41 www/tag2tagedit.php:33 #: 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." msgid "Permission denied."
msgstr "" msgstr ""
@ -1179,11 +1179,11 @@ msgstr ""
msgid "%s: Recent bookmarks" msgid "%s: Recent bookmarks"
msgstr "" msgstr ""
#: www/index.php:78 #: www/index.php:75
msgid "Store, share and tag your favourite links" msgid "Store, share and tag your favourite links"
msgstr "" msgstr ""
#: www/index.php:79 #: www/index.php:76
msgid "All Bookmarks" msgid "All Bookmarks"
msgstr "" msgstr ""
@ -1313,7 +1313,7 @@ msgstr ""
msgid "Registration failed. Please try again." msgid "Registration failed. Please try again."
msgstr "" msgstr ""
#: www/rss.php:84 #: www/rss.php:93
#, php-format #, php-format
msgid "Recent bookmarks posted to %s" msgid "Recent bookmarks posted to %s"
msgstr "" msgstr ""
@ -1358,11 +1358,11 @@ msgstr ""
msgid "Edit Link Between Tags" msgid "Edit Link Between Tags"
msgstr "" msgstr ""
#: www/tagcommondescriptionedit.php:55 #: www/tagcommondescriptionedit.php:62
msgid "Tag common description updated" msgid "Tag common description updated"
msgstr "" msgstr ""
#: www/tagcommondescriptionedit.php:58 #: www/tagcommondescriptionedit.php:67
msgid "Failed to update the tag common description" msgid "Failed to update the tag common description"
msgstr "" msgstr ""

View File

@ -11,7 +11,7 @@ foreach($users as $user) {
echo '<div class="link">'; echo '<div class="link">';
echo '<a href="'.createURL('profile', $user->getUsername()).'">'.$user->getUsername().'</a>'; 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>'; echo '</div>';
if($user->getUsername() != $currentUser->getUsername()) { if($user->getUsername() != $currentUser->getUsername()) {

View File

@ -30,7 +30,8 @@ window.onload = function() {
if(strlen($description['cdDatetime'])>0) { if(strlen($description['cdDatetime'])>0) {
echo T_('Last modification:').' '.$description['cdDatetime'].', '; echo T_('Last modification:').' '.$description['cdDatetime'].', ';
$lastUser = $userservice->getUser($description['uId']); $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> </td>

View File

@ -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>

View File

@ -1,14 +1,30 @@
<?php <?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 */ /* Service creation: only useful services are created */
$bookmarkservice =SemanticScuttle_Service_Factory::get('Bookmark'); $bookmarkservice = SemanticScuttle_Service_Factory::get('Bookmark');
$tagservice =SemanticScuttle_Service_Factory::get('Tag'); $tagservice = SemanticScuttle_Service_Factory::get('Tag');
$cdservice =SemanticScuttle_Service_Factory::get('CommonDescription'); $cdservice = SemanticScuttle_Service_Factory::get('CommonDescription');
$pageName = isset($pageName)?$pageName:""; $pageName = isset($pageName) ? $pageName : '';
$user = isset($user)?$user:""; $user = isset($user) ? $user : '';
$currenttag = isset($currenttag)?$currenttag:""; $currenttag = isset($currenttag) ? $currenttag : '';
$this->includeTemplate($GLOBALS['top_include']); $this->includeTemplate($GLOBALS['top_include']);
@ -46,12 +62,16 @@ if($currenttag!= '' && $cdservice->getLastTagDescription($currenttag)) {
} }
//common tag description edit //common tag description edit
if($userservice->isLoggedOn()) { if ($userservice->isLoggedOn()) {
if($currenttag!= '' && ($GLOBALS['enableCommonTagDescriptionEditedByAll'] || $currentUser->isAdmin())) { if ($currenttag != ''
&& ($GLOBALS['enableCommonTagDescriptionEditedByAll']
|| $currentUser->isAdmin()
)
) {
echo ' <a href="'. createURL('tagcommondescriptionedit', $currenttag).'" title="'.T_('Edit the common description of this tag').'">'; 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 !is_array($cDescription) || strlen($cDescription['cdDescription'])==0?T_('Edit the common description of this tag'):'';
echo ' <img src="'.ROOT.'images/b_edit.png" /></a>'; 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 ' (<a href="'.createURL('bookmarkcommondescriptionedit', $hash).'" title="'.T_('Edit the common description of this bookmark').'">';
echo T_('Edit the common description of this bookmark').'</a>)'; echo T_('Edit the common description of this bookmark').'</a>)';
} }
@ -101,54 +121,54 @@ $votingSort = 'voting_desc';
switch(getSortOrder()) { switch(getSortOrder()) {
case 'date_asc': case 'date_asc':
$dateArrow = ' &uarr;'; $dateArrow = ' ';
$dateSort = 'date_desc'; $dateSort = 'date_desc';
break; break;
case 'title_asc': case 'title_asc':
$titleArrow = ' &uarr;'; $titleArrow = ' ';
$titleSort = 'title_desc'; $titleSort = 'title_desc';
break; break;
case 'title_desc': case 'title_desc':
$titleArrow = ' &darr;'; $titleArrow = ' ';
$titleSort = 'title_asc'; $titleSort = 'title_asc';
break; break;
case 'voting_asc': case 'voting_asc':
$votingArrow = ' &uarr;'; $votingArrow = ' ';
$votingSort = 'voting_desc'; $votingSort = 'voting_desc';
break; break;
case 'voting_desc': case 'voting_desc':
$votingArrow = ' &darr;'; $votingArrow = ' ';
$votingSort = 'voting_asc'; $votingSort = 'voting_asc';
break; break;
case 'date_desc': case 'date_desc':
default: default:
$dateArrow = ' &darr;'; $dateArrow = ' ';
$dateSort = 'date_asc'; $dateSort = 'date_asc';
break; break;
} }
?> ?>
<a href="?sort=<?php echo $dateSort ?>"><?php echo T_("Date").$dateArrow; ?></a> <a href="?sort=<?php echo $dateSort ?>"><?php echo T_("Date").$dateArrow; ?></a>
<span>/</span> <span>/</span>
<a href="?sort=<?php echo $titleSort ?>"><?php echo T_("Title").$titleArrow; ?></a> <a href="?sort=<?php echo $titleSort ?>"><?php echo T_("Title").$titleArrow; ?></a>
<span>/</span> <span>/</span>
<?php if ($GLOBALS['enableVoting']) { ?> <?php if ($GLOBALS['enableVoting']) { ?>
<a href="?sort=<?php echo $votingSort ?>"><?php echo T_("Voting").$votingArrow; ?></a> <a href="?sort=<?php echo $votingSort ?>"><?php echo T_("Voting").$votingArrow; ?></a>
<span>/</span> <span>/</span>
<?php } ?> <?php } ?>
<?php <?php
if($currenttag!= '') { if ($currenttag!= '') {
if($user!= '') { if ($user!= '') {
echo ' - '; echo ' - ';
echo '<a href="'. createURL('tags', $currenttag) .'">'; echo '<a href="'. createURL('tags', $currenttag) .'">';
echo T_('Bookmarks from other users for this tag').'</a>'; echo T_('Bookmarks from other users for this tag').'</a>';
//echo T_(' for these tags'); //echo T_(' for these tags');
} else if($userservice->isLoggedOn()){ } else if ($userservice->isLoggedOn()){
echo ' - '; echo ' - ';
echo '<a href="'. createURL('bookmarks', $currentUser->getUsername().'/'.$currenttag) .'">'; echo '<a href="'. createURL('bookmarks', $currentUser->getUsername().'/'.$currenttag) .'">';
echo T_('Only your bookmarks for this tag').'</a>'; echo T_('Only your bookmarks for this tag').'</a>';
@ -199,7 +219,10 @@ if($currenttag!= '') {
$brss = ''; $brss = '';
$size = count($rsschannels); $size = count($rsschannels);
for ($i = 0; $i < $size; $i++) { 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"; $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 .'"' : ''); ?> <ol<?php echo ($start > 0 ? ' start="'. ++$start .'"' : ''); ?> id="bookmarks">
id="bookmarks"> <?php
<?php
$addresses = array(); $addresses = array();
foreach ($bookmarks as $key => &$row) { foreach ($bookmarks as $key => &$row) {
$addresses[$row['bId']] = $row['bAddress']; $addresses[$row['bId']] = $row['bAddress'];
@ -253,35 +274,52 @@ if($currenttag!= '') {
$tagsForCopy = ''; $tagsForCopy = '';
$tags = $row['tags']; $tags = $row['tags'];
foreach ($tags as $tkey => &$tag) { foreach ($tags as $tkey => &$tag) {
$cats .= '<a href="'. sprintf($cat_url, filter($row['username'], 'url'), filter($tag, 'url')) .'" rel="tag">'. filter($tag) .'</a>, '; $tagcaturl = sprintf(
$tagsForCopy.= $tag.','; $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); $cats = substr($cats, 0, -2);
if ($cats != '') { if ($cats != '') {
$cats = ' '.T_('Tags:').' '. $cats; $cats = T_('Tags:') . ' ' . $cats;
} }
// Edit and delete links // Edit and delete links
$edit = ''; $edit = '';
if ($bookmarkservice->editAllowed($row)) { 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 // 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 // User attribution
$copy = ' '. T_('by'). ' '; $copy = ' ' . T_('by') . ' ';
if($userservice->isLoggedOn() && $currentUser->getUsername() == $row['username']) { if ($userservice->isLoggedOn()
$copy.= T_('you'); && $currentUser->getUsername() == $row['username']
) {
$copy .= T_('you');
} else { } 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)) { if (!isset($hash)) {
$others = $otherCounts[$row['bAddress']]; $others = $otherCounts[$row['bAddress']];
$ostart = '<a href="'. createURL('history', $row['bHash']) .'">'; $ostart = '<a href="' . createURL('history', $row['bHash']) . '">';
$oend = '</a>'; $oend = '</a>';
switch ($others) { switch ($others) {
case 0: case 0:
@ -300,7 +338,10 @@ if($currenttag!= '') {
&& !$existence[$row['bAddress']] && !$existence[$row['bAddress']]
) { ) {
$copy .= ' - <a href="' $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.').'">' . '" title="'.T_('Copy this bookmark to YOUR bookmarks.').'">'
. T_('Copy') . T_('Copy')
. '</a>'; . '</a>';
@ -321,7 +362,7 @@ if($currenttag!= '') {
// Admin specific design // Admin specific design
if ($userservice->isAdmin($row['username']) && $GLOBALS['enableAdminColors']) { if ($userservice->isAdmin($row['username']) && $GLOBALS['enableAdminColors']) {
$adminBgClass = 'class="adminBackground"'; $adminBgClass = ' class="adminBackground"';
$adminStar = ' <img src="'. ROOT .'images/logo_24.gif" width="12px" title="'. T_('This bookmark is certified by an admin user.') .'" />'; $adminStar = ' <img src="'. ROOT .'images/logo_24.gif" width="12px" title="'. T_('This bookmark is certified by an admin user.') .'" />';
} else { } else {
$adminBgClass = ''; $adminBgClass = '';
@ -346,13 +387,16 @@ if($currenttag!= '') {
} }
// Output // Output
echo '<li class="xfolkentry'. $access .'" >'."\n"; echo ' <li class="xfolkentry'. $access .'">'."\n";
include 'bookmarks-thumbnail.inc.tpl.php'; include 'bookmarks-thumbnail.inc.tpl.php';
include 'bookmarks-vote.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'] == '') { if ($row['bDescription'] == '') {
$bkDescription = $GLOBALS['blankDescription']; $bkDescription = $GLOBALS['blankDescription'];
} else { } 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 $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"; echo ' <div class="description">'. nl2br($bkDescription) ."</div>\n";
//if(!isset($hash)) { echo ' <div class="address">' . shortenString($oaddress) . "</div>\n";
echo '<div class="address">' . shortenString($oaddress) . '</div>';
//}
echo '<div class="meta">'. $cats . $copy . $edit . $update ."</div>\n"; echo ' <div class="meta">'
echo $privateNoteField!=''?'<div class="privateNote" title="'. T_('Private Note on this bookmark') .'">'.$privateNoteField."</div>\n":''; . $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'; include 'bookmarks-vote-horizontal.inc.tpl.php';
echo '</div>'; echo " </div>\n";
echo "</li>\n"; echo " </li>\n";
} }
?> ?>

View File

@ -36,28 +36,40 @@ $allPopularTagsCount = count($allPopularTags);
// function printing the cloud // function printing the cloud
function writeTagsProposition($tagsCloud, $title) { function writeTagsProposition($tagsCloud, $title)
echo 'document.write(\'<div class="collapsible">\');'; {
echo 'document.write(\'<h3>'. $title .'<\/h3>\');'; static $id = 0;
echo 'document.write(\'<p id="popularTags" class="tags">\');'; ++$id;
echo <<<JS
$('.edit-tagclouds')
.append(
'<div class="collapsible" id="edit-tagcloud-$id">'
+ ' <h3>$title</h3>'
+ ' <p class="popularTags tags"></p>'
+ '</div>');
JS;
$taglist = ''; $taglist = '';
foreach(array_keys($tagsCloud) as $key) { foreach (array_keys($tagsCloud) as $key) {
$row =& $tagsCloud[$key]; $row = $tagsCloud[$key];
$entries = T_ngettext('bookmark', 'bookmarks', $row['bCount']); $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 '$(\'#edit-tagcloud-' . $id . ' p\').append('
echo 'document.write(\''. $taglist .'\');'; . json_encode($taglist)
echo 'document.write(\'<\/p>\');'; . ");\n";
echo 'document.write(\'<\/div>\');';
} }
if ($allPopularTagsCount > 0 || $userPopularTagsCount > 0 ) { ?> if ($allPopularTagsCount > 0 || $userPopularTagsCount > 0 ) { ?>
<script type="text/javascript"> <script type="text/javascript">
//<![CDATA[
Array.prototype.contains = function (ele) { Array.prototype.contains = function (ele) {
for (var i = 0; i < this.length; i++) { for (var i = 0; i < this.length; i++) {
if (this[i] == ele) { if (this[i] == ele) {
@ -87,20 +99,26 @@ function addonload(addition) {
} }
} }
addonload( jQuery(function($) {
function () { <?php
var taglist = document.getElementById('tags'); if ($userPopularTagsCount > 0) {
var tags = taglist.value.split(', '); 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++) { for (var i = 0; i < populartags.length; i++) {
if (tags.contains(populartags[i].innerHTML)) { if (tags.contains(populartags[i].innerHTML)) {
populartags[i].className = 'selected'; populartags[i].className = 'selected';
} }
} }
} });
);
function addTag(ele) { function addTag(ele) {
var thisTag = ele.innerHTML; var thisTag = ele.innerHTML;
@ -122,20 +140,9 @@ function addTag(ele) {
document.getElementById('tags').focus(); 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> </script>
<div class="edit-tagclouds"></div>
<?php <?php
} }
?> ?>

View File

@ -16,33 +16,41 @@ switch ($row['bStatus']) {
break; break;
} }
$this->includeTemplate("dojo.inc");
function jsEscTitle($title) function jsEscTitle($title)
{ {
return addcslashes($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);
}
if (is_array($row['tags'])) {
$row['tags'] = implode(', ', $row['tags']);
}
$ajaxUrl = ROOT . 'ajax/'
. (
($GLOBALS['adminsAreAdvisedTagsFromOtherAdmins'] && $currentUser->isAdmin())
? 'getadmintags'
: 'getcontacttags'
) . '.php';
?> ?>
<script type="text/javascript">
//window.onload = function() {
// document.getElementById("address").focus();
//}
</script>
<form action="<?php echo $formaction; ?>" method="post"> <form action="<?php echo $formaction; ?>" method="post">
<table> <table>
<tr> <tr>
<th align="left"><?php echo T_('Address'); ?></th> <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><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>
<tr> <tr>
<th align="left"><?php echo T_('Title'); ?></th> <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><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>
<tr> <tr>
<th align="left"> <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> <a onclick="var nz = document.getElementById('privateNoteZone'); nz.style.display='';this.style.display='none';"><?php echo T_("Add Note"); ?></a>
</th> </th>
<td><textarea name="description" id="description" rows="5" cols="63" ><?php echo filter($row['bDescription'], 'xml'); ?></textarea></td> <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): ?> <?php if(count($GLOBALS['descriptionAnchors'])>0): ?>
<br /><br /> <br /><br />
<?php echo T_('Suggested anchors: '); ?> <?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; ?>> <tr id="privateNoteZone" <?php if(strlen($row['bPrivateNote'])==0):?>style="display:none"<?php endif; ?>>
<th align="left"><?php echo T_('Private Note'); ?></th> <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><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> </td>
</tr> </tr>
<tr> <tr>
<th align="left"><?php echo T_('Tags'); ?></th> <th align="left"><?php echo T_('Tags'); ?></th>
<td class="scuttletheme"> <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" id="tags" name="tags" size="75" value="<?php echo filter($row['tags'], 'xml'); ?>"/>
<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>
<td>&larr; <?php echo T_('Comma-separated'); ?></td> <td> <?php echo T_('Comma-separated'); ?></td>
</tr> </tr>
<tr> <tr>
<th></th> <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>
<tr> <tr>
<th></th> <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>
<tr> <tr>
<th align="left"><?php echo T_('Privacy'); ?></th> <th align="left"><?php echo T_('Privacy'); ?></th>
@ -124,52 +132,83 @@ function jsEscTitle($title)
?> ?>
</td> </td>
<td></td> <td></td>
</tr> </tr>
</table> </table>
</form> </form>
<link href="<?php echo ROOT ?>js/jquery-ui-1.8.11/themes/base/jquery.ui.all.css" rel="stylesheet" type="text/css"/>
<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">
//<![CDATA[
jQuery(document).ready(function() {
function split(val)
{
return val.split(/[,=><]\s*/);
}
function extractLast(term)
{
return split(term).pop();
}
//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 <?php
// Dynamic tag selection // Dynamic tag selection
$this->includeTemplate('dynamictags.inc'); $this->includeTemplate('dynamictags.inc');
// Bookmarklets and import links // Bookmarklets and import links
if (empty($_REQUEST['popup']) && (!isset($showdelete) || !$showdelete)) { if (empty($_REQUEST['popup']) && (!isset($showdelete) || !$showdelete)) {
$this->includeTemplate('bookmarklet.inc.php');
?> ?>
<h3><?php echo T_('Bookmarklet'); ?></h3>
<p>
<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")
{
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>');
}
else
{
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>');
}
document.write('<\/ul>');
</script>
<h3><?php echo T_('Import'); ?></h3> <h3><?php echo T_('Import'); ?></h3>
<ul> <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> <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>

View File

@ -3,9 +3,7 @@ $this->includeTemplate($GLOBALS['top_include']);
?> ?>
<form action="<?php echo $formaction; ?>" method="post"> <form action="<?php echo $formaction; ?>" method="post">
<input type="hidden" name="token" value="<?php echo $token; ?>"> <input type="hidden" name="token" value="<?php echo $token; ?>"/>
</table>
<h3><?php echo T_('Account Details'); ?></h3> <h3><?php echo T_('Account Details'); ?></h3>
@ -28,7 +26,7 @@ $this->includeTemplate($GLOBALS['top_include']);
<tr> <tr>
<th align="left"><?php echo T_('E-mail'); ?></th> <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><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> </tr>
</table> </table>
@ -58,7 +56,7 @@ $this->includeTemplate($GLOBALS['top_include']);
<th align="left"><?php echo T_('Export bookmarks'); ?></th> <th align="left"><?php echo T_('Export bookmarks'); ?></th>
<td> <td>
<a href="../api/export_html.php"><?php echo T_('HTML file (for browsers)')?></a> / <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> <a href="../api/export_csv.php"><?php echo T_('CSV file (for spreadsheet tools)')?></a>
</td> </td>
</tr> </tr>

View File

@ -1,4 +1,11 @@
<?php <?php
/*
* Used in:
* - populartags.php
* - bookmarks.php
* - alltags.php
* - tags.php
*/
/* Service creation: only useful services are created */ /* Service creation: only useful services are created */
$tag2tagservice =SemanticScuttle_Service_Factory::get('Tag2Tag'); $tag2tagservice =SemanticScuttle_Service_Factory::get('Tag2Tag');
@ -8,98 +15,52 @@ require_once('sidebar.linkedtags.inc.php');
$user = isset($user)?$user:''; $user = isset($user)?$user:'';
$userid = isset($userid)?$userid:0; $userid = isset($userid)?$userid:0;
$currenttag = isset($currenttag)?$currenttag:''; $currenttag = isset($currenttag)?$currenttag:'';
$summarizeLinkedTags = isset($summarizeLinkedTags)?$summarizeLinkedTags:false; //$summarizeLinkedTags = isset($summarizeLinkedTags)?$summarizeLinkedTags:false;
$logged_on_userid = $userservice->getCurrentUserId(); $logged_on_userid = $userservice->getCurrentUserId();
if ($logged_on_userid === false) { $editingMode = $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'];
}
}
?> ?>
<h2><?php echo T_('Linked Tags'); ?></h2>
<div id="related">
<?php <?php
if(($logged_on_userid != null) && ($userid === $logged_on_userid)) { if ($editingMode) {
$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) {
echo '<p style="margin-bottom: 13px;text-align:center;">'; 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('tag2tagadd','') .'" rel="tag">'.T_('Add new link').'</a>) ';
echo ' (<a href="'. createURL('tag2tagdelete','') .'" rel="tag">'.T_('Delete link').'</a>)'; echo ' (<a href="'. createURL('tag2tagdelete','') .'" rel="tag">'.T_('Delete link').'</a>)';
echo '</p>'; echo '</p>';
} }
?>
if(strlen($user)==0) { <div id="related-content"></div>
$cat_url = createURL('tags', '%2$s'); <script type="text/javascript">//<![CDATA[
} jQuery("#related-content")
.jstree({
$stopList = array(); "themes" : {
foreach($explodedTags as $explodedTag) { "theme": "default",
if(!in_array($explodedTag, $stopList)) { "dots": false,
"icons": true,
"url": '<?php echo ROOT_JS ?>themes/default/style.css'
},
// fathers tag "json_data" : {
$fatherTags = $tag2tagservice->getLinkedTags($explodedTag, '>', $userid, true); "ajax" : {
if(count($fatherTags)>0) { "url": function(node) {
foreach($fatherTags as $fatherTag) { //-1 is root
echo '<a href="'. sprintf($cat_url, filter($user, 'url'), filter($fatherTag, 'url')) .'" rel="tag">('. filter($fatherTag) .')</a> '; parentparam = "";
} if (node == -1 ) {
} node = <?php echo json_encode($currenttag); ?>;
/* parentparam = "&parent=true";
$displayLinkedTags = displayLinkedTags($explodedTag, '>', $userid, $cat_url, $user, $editingMode, null, 1); } else if (node.attr('rel')) {
echo $displayLinkedTags['output']; node = node.attr('rel');
if(is_array($displayLinkedTags['stopList'])) { } else {
$stopList = array_merge($stopList, $displayLinkedTags['stopList']); return;
}*/
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>';
} }
} return "<?php echo ROOT ?>ajax/getlinkedtags.php?tag=" + node
?> </div> + parentparam;
}
<?php endif?> }
},
plugins : [ "themes", "json_data"]
});
//]]>
</script>
</div>

View File

@ -65,13 +65,13 @@ if (sizeof($menuTags) > 0 || ($userid != 0 && $userid === $logged_on_userid)) {
<?php $cUser = $userservice->getUser($userid); ?> <?php $cUser = $userservice->getUser($userid); ?>
<?php if($userid>0): ?> <?php if($userid>0): ?>
<?php if($userid==$logged_on_userid): ?> <?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: ?> <?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 endif; ?>
<?php else : ?> <?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; ?> <?php endif; ?>
</div> </div>

View File

@ -1,7 +1,4 @@
<?php <?php
/* Service creation: only useful services are created */
$tag2tagservice =SemanticScuttle_Service_Factory::get('Tag2Tag');
require_once('sidebar.linkedtags.inc.php'); require_once('sidebar.linkedtags.inc.php');
/* Manage input */ /* 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']; $menu2Tags = $GLOBALS['menu2Tags'];
if (sizeOf($menu2Tags) > 0) { if (count($menu2Tags) > 0) {
$this->includeTemplate("dojo.inc"); ?>
?>
<h2><?php echo T_('Featured Menu Tags');?></h2> <h2><?php echo T_('Featured Menu Tags');?></h2>
<div id="maintagsmenu" <div id="maintagsmenu"
<?php echo 'title="'.T_('This menu is composed of keywords (tags) organized by admins.').'"'?>> <?php echo 'title="'.T_('This menu is composed of keywords (tags) organized by admins.').'"'?>>
<ul>
<?php <?php
foreach($menu2Tags as $menu2Tag) { //this is unneeded and replaced by the ajax tree anyway. we keep it for
// non-js browsers
echo '<div dojoType="dojo.data.ItemFileReadStore" url="'.ROOT.'ajax/getadminlinkedtags.php?tag='.filter($menu2Tag, 'url').'" jsid="linkedTagStore" ></div>'; foreach ($menu2Tags as $menu2Tag) {
echo '<div dojoType="dijit.Tree" store="linkedTagStore" labelAttr="name" >'; echo ' <li>'
echo '<script type="dojo/method" event="onClick" args="item">'; . sprintf(
$returnUrl = sprintf($cat_url, filter($user, 'url'), filter('', 'url')); '<a href="%s">%s</a>',
echo 'window.location = "'.$returnUrl.'"+item.name'; sprintf($cat_url, $menu2Tag),
echo '</script>'; $menu2Tag
//echo '<script type="dojo/method" event="getLabel" args="item">'; )
//echo 'return item.name + "...";'; . '</li>' . "\n";
//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>';
} }
?> ?>
</ul>
</div> </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 <?php
} }
?> ?>

View File

@ -31,7 +31,7 @@ if ($recentTags && count($recentTags) > 0) {
} }
echo $contents ."</p>\n"; 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> </div>
<?php <?php

View File

@ -1,35 +1,50 @@
<?php <?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 */ /* Service creation: only useful services are created */
$searchhistoryservice =SemanticScuttle_Service_Factory::get('SearchHistory'); $searchhistoryservice = SemanticScuttle_Service_Factory::get('SearchHistory');
$logged_on_userid = $userservice->getCurrentUserId(); $lastSearches = $searchhistoryservice->getAllSearches(
if ($logged_on_userid === false) { 'all', NULL, 3, NULL, true, false
$logged_on_userid = NULL; );
}
$lastSearches = $searchhistoryservice->getAllSearches('all', NULL, 3, NULL, true, false);
if ($lastSearches && count($lastSearches) > 0) { if ($lastSearches && count($lastSearches) > 0) {
?> ?>
<h2><?php echo T_('Last Searches'); ?></h2> <h2><?php echo T_('Last Searches'); ?></h2>
<div id="searches"> <div id="searches">
<table> <table>
<?php <?php
foreach ($lastSearches as $row) { foreach ($lastSearches as $row) {
echo '<tr><td>'; echo ' <tr><td>';
echo '<a href="' . htmlspecialchars( echo '<a href="'
createURL('search', $range.'/'.$row['shTerms']) . htmlspecialchars(createURL('search', $range.'/'.$row['shTerms']))
) . '">'; . '">';
echo htmlspecialchars($row['shTerms']); echo htmlspecialchars($row['shTerms']);
echo '</a>'; echo '</a>';
echo ' <span title="'.T_('Number of bookmarks for this query').'">('.$row['shNbResults'].')</span>'; echo ' <span title="'
echo '</td></tr>'; . T_('Number of bookmarks for this query')
. '">(' . $row['shNbResults'] . ')</span>';
echo '</td></tr>' . "\n";
} }
//echo '<tr><td><a href="'.createURL('users').'">...</a></td></tr>'; //echo '<tr><td><a href="'.createURL('users').'">...</a></td></tr>';
?> ?>
</table> </table>
</div> </div>
<?php <?php
} }

View File

@ -18,7 +18,7 @@ if ($lastUsers && count($lastUsers) > 0) {
foreach ($lastUsers as $row) { foreach ($lastUsers as $row) {
echo '<tr><td>'; echo '<tr><td>';
echo '<a href="'.createURL('profile', $row['username']).'">'; echo '<a href="'.createURL('profile', $row['username']).'">';
echo $row['username']; echo SemanticScuttle_Model_UserArray::getName($row);
echo '</a>'; echo '</a>';
echo ' (<a href="'.createURL('bookmarks', $row['username']).'">'.T_('bookmarks').'</a>)'; echo ' (<a href="'.createURL('bookmarks', $row['username']).'">'.T_('bookmarks').'</a>)';
echo '</td></tr>'; echo '</td></tr>';
@ -27,7 +27,7 @@ foreach ($lastUsers as $row) {
?> ?>
</table> </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> </div>
<?php <?php
} }

View File

@ -16,7 +16,7 @@ foreach($watching as $watchuser) {
?> ?>
<?php if(count($closeContacts)>0):?> <?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"> <div id="watching">
<ul> <ul>
<?php foreach($closeContacts as $watchuser): ?> <?php foreach($closeContacts as $watchuser): ?>
@ -27,7 +27,7 @@ foreach($watching as $watchuser) {
<?php endif; ?> <?php endif; ?>
<h2><?php echo ' &rarr; '. T_('Watching'); ?></h2> <h2><?php echo ' '. T_('Watching'); ?></h2>
<div id="watching"> <div id="watching">
<ul> <ul>
<?php if($userservice->isLoggedOn() && $currentUser->getUsername() == $user): ?> <?php if($userservice->isLoggedOn() && $currentUser->getUsername() == $user): ?>
@ -41,7 +41,7 @@ foreach($watching as $watchuser) {
<?php foreach($watching as $watchuser): ?> <?php foreach($watching as $watchuser): ?>
<li><a href="<?php echo createURL('bookmarks', $watchuser); ?>"><?php echo $watchuser; ?></a> <li><a href="<?php echo createURL('bookmarks', $watchuser); ?>"><?php echo $watchuser; ?></a>
<?php if($userservice->isLoggedOn() && $currentUser->getUsername() == $user): ?> <?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> </li>
<?php endif; ?> <?php endif; ?>
<?php endforeach; ?> <?php endforeach; ?>
@ -49,7 +49,7 @@ foreach($watching as $watchuser) {
</ul> </ul>
</div> </div>
<h2><?php echo ' &larr; '. T_('Watched By'); ?></h2> <h2><?php echo ' '. T_('Watched By'); ?></h2>
<div id="watching"> <div id="watching">
<ul> <ul>
<?php foreach($watchedBy as $watchuser): ?> <?php foreach($watchedBy as $watchuser): ?>

View File

@ -4,7 +4,7 @@ $this->includeTemplate($GLOBALS['top_include']);
<form action="<?php echo $formaction; ?>" method="post"> <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 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/> <small style="text-align:right"><?php echo T_('Note: use ">" to include one tag in another. e.g.: europe>france>paris')?></small><br/>
</p> </p>

View File

@ -20,7 +20,8 @@ window.onload = function() {
if(strlen($description['cdDatetime'])>0) { if(strlen($description['cdDatetime'])>0) {
echo T_('Last modification:').' '.$description['cdDatetime'].', '; echo T_('Last modification:').' '.$description['cdDatetime'].', ';
$lastUser = $userservice->getUser($description['uId']); $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> </td>

View File

@ -11,12 +11,12 @@ window.onload = function() {
<tr> <tr>
<th align="left"><?php echo T_('Old'); ?></th> <th align="left"><?php echo T_('Old'); ?></th>
<td><input type="text" name="old" id="old" value="<?php echo $old; ?>" /></td> <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>
<tr> <tr>
<th align="left"><?php echo T_('New'); ?></th> <th align="left"><?php echo T_('New'); ?></th>
<td><input type="text" name="new" id="new" value="" /></td> <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>
<tr> <tr>
<td></td> <td></td>

View File

@ -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"> <!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"> <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
<head> <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> <title><?php echo filter($GLOBALS['sitename'] .(isset($pagetitle) ? ' » ' . $pagetitle : '')); ?></title>
<link rel="icon" type="image/png" href="<?php echo ROOT ?>icon.png" /> <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="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']) ?>"/> <link rel="search" type="application/opensearchdescription+xml" href="<?php echo ROOT ?>api/opensearch.php" title="<?php echo htmlspecialchars($GLOBALS['sitename']) ?>"/>
<?php <?php
if(isset($rsschannels)) { if (isset($rsschannels)) {
$size = count($rsschannels); $size = count($rsschannels);
for ($i = 0; $i < $size; $i++) { 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 (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> <script type="text/javascript" src="<?php echo ROOT ?>jsScuttle.php"></script>
<?php endif ?> <?php endif ?>
</head> </head>
<body>
<body class="nihilo">
<!-- the class is used by Dojo widgets -->
<?php <?php
$headerstyle = ''; $headerstyle = '';

View File

@ -14,7 +14,14 @@ if ($users && count($users) > 0) {
<?php <?php
$contents = '<'; $contents = '<';
foreach ($users as $row) { 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> </ul>

View File

@ -1,9 +1,34 @@
ChangeLog for SemantiScuttle 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 0.97.0 - 2010-06-09

View File

@ -39,7 +39,12 @@
- Make users inactive by default when registered newly - Make users inactive by default when registered newly
- have to be activated by admins (see #1926991) - have to be activated by admins (see #1926991)
- Add RDFa to user profile page - Add RDFa to user profile page
- use recaptcha or alike -> quickform
- tutorial about sidebar - 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

10
doc/developers/api Normal file
View File

@ -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

9
doc/developers/doc-TODO Normal file
View File

@ -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?

View File

@ -4,8 +4,8 @@ How to release a new version of SemanticScuttle
0. Run unit tests and verify that all of them pass 0. Run unit tests and verify that all of them pass
1. Update doc/ChangeLog 1. Update doc/ChangeLog
2. Update doc/UPGRADE.txt 2. Update doc/UPGRADE.txt
3. Update version in data/templates/about.tpl.php 3. Update version in data/templates/about.tpl.php,
and build.xml build.xml and doc/README.txt
4. Create a release zip file via the build script: 4. Create a release zip file via the build script:
Just type "phing". Just type "phing".
5. Make a test installation from your zip file with a fresh 5. Make a test installation from your zip file with a fresh

View File

@ -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. 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, In case you added a new string to the code that needs translation,
update the base translation file by running 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 After that has been done, the changes to the base messages.po file
need to be merged into the single language translation files, need to be merged into the single language translation files,

1
html.properties Normal file
View File

@ -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>

26
scripts/database-dump.php Normal file
View File

@ -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'
);
?>

View File

@ -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)
);
?>

View File

@ -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;
}
}
?>

View File

@ -15,7 +15,7 @@
/** /**
* SemanticScuttle user object. * SemanticScuttle user object.
* Rare fields are filled if required. * Rarely used fields are filled if required.
* *
* @category Bookmarking * @category Bookmarking
* @package SemanticScuttle * @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" * @return string Datetime value: "YYYY-MM-DD HH:MM:SS"
*/ */

View File

@ -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'];
}
}
?>

View File

@ -12,6 +12,7 @@
* @license GPL http://www.gnu.org/licenses/gpl.html * @license GPL http://www.gnu.org/licenses/gpl.html
* @link http://sourceforge.net/projects/semanticscuttle * @link http://sourceforge.net/projects/semanticscuttle
*/ */
require_once 'SemanticScuttle/Model/RemoteUser.php';
/** /**
* SemanticScuttle bookmark service. * 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) public function __construct($db)
{ {
$this->db = $db; $this->db = $db;
@ -168,7 +176,10 @@ class SemanticScuttle_Service_Bookmark extends SemanticScuttle_DbService
* Retrieves a bookmark with the given URL. * Retrieves a bookmark with the given URL.
* DOES NOT RESPECT PRIVACY SETTINGS! * 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 * @return mixed Array with bookmark data or false in case
* of an error (i.e. not found). * of an error (i.e. not found).
@ -176,9 +187,9 @@ class SemanticScuttle_Service_Bookmark extends SemanticScuttle_DbService
* @uses getBookmarkByHash() * @uses getBookmarkByHash()
* @see getBookmarkByShortname() * @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);
} }
@ -188,15 +199,18 @@ class SemanticScuttle_Service_Bookmark extends SemanticScuttle_DbService
* DOES NOT RESPECT PRIVACY SETTINGS! * 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 * @return mixed Array with bookmark data or false in case
* of an error (i.e. not found). * of an error (i.e. not found).
* *
* @see getHash() * @see getHash()
*/ */
public function getBookmarkByHash($hash) public function getBookmarkByHash($hash, $all = true)
{ {
return $this->_getbookmark('bHash', $hash, true); return $this->_getbookmark('bHash', $hash, $all);
} }
@ -240,17 +254,17 @@ class SemanticScuttle_Service_Bookmark extends SemanticScuttle_DbService
* Counts bookmarks for a user. * Counts bookmarks for a user.
* *
* @param integer $uId User ID * @param integer $uId User ID
* @param string $range Range of bookmarks: * @param string $status Bookmark visibility/privacy settings:
* 'public', 'shared', 'private' * 'public', 'shared', 'private'
* or 'all' * or 'all'
* *
* @return integer Number of bookmarks * @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 = 'SELECT COUNT(*) as "0" FROM '. $this->getTableName();
$sql.= ' WHERE uId = ' . intval($uId); $sql.= ' WHERE uId = ' . intval($uId);
switch ($range) { switch ($status) {
case 'all': case 'all':
//no constraints //no constraints
break; break;
@ -425,7 +439,7 @@ class SemanticScuttle_Service_Bookmark extends SemanticScuttle_DbService
* @param string $title Bookmark title * @param string $title Bookmark title
* @param string $description Long bookmark description * @param string $description Long bookmark description
* @param string $privateNote Private note for the user. * @param string $privateNote Private note for the user.
* @param string $status Bookmark visibility: * @param string $status Bookmark visibility / privacy settings:
* 0 - public * 0 - public
* 1 - shared * 1 - shared
* 2 - private * 2 - private
@ -453,14 +467,6 @@ class SemanticScuttle_Service_Bookmark extends SemanticScuttle_DbService
$address = $this->normalize($address); $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 * Note that if date is NULL, then it's added with a date and
* time of now, and if it's present, * 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. // Set up the SQL insert statement and execute it.
$values = array( $values = array(
'uId' => intval($sId), 'uId' => intval($sId),
'bIp' => $ip, 'bIp' => SemanticScuttle_Model_RemoteUser::getIp(),
'bDatetime' => $datetime, 'bDatetime' => $datetime,
'bModified' => $datetime, 'bModified' => $datetime,
'bTitle' => $title, 'bTitle' => $title,
@ -548,7 +554,7 @@ class SemanticScuttle_Service_Bookmark extends SemanticScuttle_DbService
* @param string $title Bookmark title * @param string $title Bookmark title
* @param string $description Long bookmark description * @param string $description Long bookmark description
* @param string $privateNote Private note for the user. * @param string $privateNote Private note for the user.
* @param string $status Bookmark visibility: * @param string $status Bookmark visibility / privacy setting:
* 0 - public * 0 - public
* 1 - shared * 1 - shared
* 2 - private * 2 - private
@ -570,15 +576,7 @@ class SemanticScuttle_Service_Bookmark extends SemanticScuttle_DbService
return false; return false;
} }
// Get the client's IP address and the date; note that the date is in GMT. // Get the 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');
$moddatetime = gmdate('Y-m-d H:i:s', time()); $moddatetime = gmdate('Y-m-d H:i:s', time());
$address = $this->normalize($address); $address = $this->normalize($address);
@ -589,7 +587,11 @@ class SemanticScuttle_Service_Bookmark extends SemanticScuttle_DbService
if ($bookmark['bAddress'] != $address if ($bookmark['bAddress'] != $address
&& $this->bookmarkExists($address, $bookmark['uId']) && $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; return false;
} }
@ -611,15 +613,20 @@ class SemanticScuttle_Service_Bookmark extends SemanticScuttle_DbService
if (!is_null($date)) { if (!is_null($date)) {
$datetime = gmdate('Y-m-d H:i:s', strtotime($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'); $this->db->sql_transaction('begin');
if (!($dbresult = & $this->db->sql_query($sql))) { if (!($dbresult = & $this->db->sql_query($sql))) {
$this->db->sql_transaction('rollback'); $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);
@ -629,7 +636,10 @@ class SemanticScuttle_Service_Bookmark extends SemanticScuttle_DbService
$b2tservice = SemanticScuttle_Service_Factory :: get('Bookmark2Tag'); $b2tservice = SemanticScuttle_Service_Factory :: get('Bookmark2Tag');
if (!$b2tservice->attachTags($bId, $categories, $fromApi, $extension)) { if (!$b2tservice->attachTags($bId, $categories, $fromApi, $extension)) {
$this->db->sql_transaction('rollback'); $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'); $this->db->sql_transaction('commit');
@ -724,7 +734,8 @@ class SemanticScuttle_Service_Bookmark extends SemanticScuttle_DbService
if (SQL_LAYER == 'mysql4') { if (SQL_LAYER == 'mysql4') {
$query_1 .= 'SQL_CALC_FOUND_ROWS '; $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' $query_2 = ' FROM '. $userservice->getTableName() .' AS U'
. ', '. $this->getTableName() .' AS B'; . ', '. $this->getTableName() .' AS B';
@ -745,7 +756,7 @@ class SemanticScuttle_Service_Bookmark extends SemanticScuttle_DbService
$arrWatch = $userservice->getWatchlist($user); $arrWatch = $userservice->getWatchlist($user);
if (count($arrWatch) > 0) { if (count($arrWatch) > 0) {
$query_3_1 = ''; $query_3_1 = '';
foreach($arrWatch as $row) { foreach ($arrWatch as $row) {
$query_3_1 .= 'B.uId = '. intval($row) .' OR '; $query_3_1 .= 'B.uId = '. intval($row) .' OR ';
} }
$query_3_1 = substr($query_3_1, 0, -3); $query_3_1 = substr($query_3_1, 0, -3);
@ -756,7 +767,7 @@ class SemanticScuttle_Service_Bookmark extends SemanticScuttle_DbService
} }
$query_5 = ''; $query_5 = '';
if($hash == null) { if ($hash == null) {
$query_5.= ' GROUP BY B.bHash'; $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_2 .= ', '. $b2tservice->getTableName() .' AS T'. $i;
$query_4 .= ' AND ('; $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) { while (is_array($allLinkedTags) && count($allLinkedTags)>0) {
$query_4 .= ' T'. $i .'.tag = "'. array_pop($allLinkedTags) .'"'; $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 // Search terms in tags as well when none given
if (!count($tags)) { 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; $dotags = true;
} else { } else {
$dotags = false; $dotags = false;
@ -833,12 +847,24 @@ class SemanticScuttle_Service_Bookmark extends SemanticScuttle_DbService
$query_4 = ''; $query_4 = '';
for ($i = 0; $i < count($aTerms); $i++) { for ($i = 0; $i < count($aTerms); $i++) {
$query_4 .= ' AND (B.bTitle LIKE "%'. $this->db->sql_escape($aTerms[$i]) .'%"'; $query_4 .= ' AND (B.bTitle LIKE "%'
$query_4 .= ' OR B.bDescription LIKE "%'. $this->db->sql_escape($aTerms[$i]) .'%"'; . $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 .= ' 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) { 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 .= ')'; $query_4 .= ')';
} }
@ -860,22 +886,35 @@ class SemanticScuttle_Service_Bookmark extends SemanticScuttle_DbService
$query = $query_1 . $query_2 . $query_3 . $query_4 . $query_5; $query = $query_1 . $query_2 . $query_3 . $query_4 . $query_5;
if (!($dbresult = & $this->db->sql_query_limit($query, intval($perpage), intval($start)))) { $dbresult = $this->db->sql_query_limit(
message_die(GENERAL_ERROR, 'Could not get bookmarks', '', __LINE__, __FILE__, $query, $this->db); $query, intval($perpage), intval($start)
);
if (!$dbresult) {
message_die(
GENERAL_ERROR, 'Could not get bookmarks',
'', __LINE__, __FILE__, $query, $this->db
);
} }
if (SQL_LAYER == 'mysql4') { if (SQL_LAYER == 'mysql4') {
$totalquery = 'SELECT FOUND_ROWS() AS total'; $totalquery = 'SELECT FOUND_ROWS() AS total';
} else { } else {
if ($hash) { 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 { } 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)))) { if (!($totalresult = $this->db->sql_query($totalquery))
message_die(GENERAL_ERROR, 'Could not get total bookmarks', '', __LINE__, __FILE__, $totalquery, $this->db); || (!($row = $this->db->sql_fetchrow($totalresult)))
) {
message_die(
GENERAL_ERROR, 'Could not get total bookmarks',
'', __LINE__, __FILE__, $totalquery, $this->db
);
} }
$total = $row['total']; $total = $row['total'];
@ -962,10 +1001,14 @@ class SemanticScuttle_Service_Bookmark extends SemanticScuttle_DbService
*/ */
public function deleteBookmarksForUser($uId) 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))) { if (!($dbresult = $this->db->sql_query($query))) {
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 true; return true;
@ -977,12 +1020,6 @@ class SemanticScuttle_Service_Bookmark extends SemanticScuttle_DbService
* Counts the number of bookmarks that have the same address * Counts the number of bookmarks that have the same address
* as the given 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 * @param string|array $addresses Address/URL to look for, string
* of one address or array with * of one address or array with
* multiple ones * multiple ones
@ -991,6 +1028,12 @@ class SemanticScuttle_Service_Bookmark extends SemanticScuttle_DbService
* In case $addresses was an array, key-value array * In case $addresses was an array, key-value array
* with key being the address, value said number of * with key being the address, value said number of
* bookmarks * 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) public function countOthers($addresses)
{ {

View File

@ -454,58 +454,155 @@ class SemanticScuttle_Service_Bookmark2Tag extends SemanticScuttle_DbService
return $output; 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 // look for admin ids
$userservice = SemanticScuttle_Service_Factory :: get('User'); $userservice = SemanticScuttle_Service_Factory::get('User');
$adminIds = $userservice->getAdminIds(); $adminIds = $userservice->getAdminIds();
// ask for their tags // 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 // look for contact ids
$userservice = SemanticScuttle_Service_Factory :: get('User'); $userservice = SemanticScuttle_Service_Factory::get('User');
$contacts = $userservice->getWatchlist($user); $contacts = $userservice->getWatchlist($user);
// add the user (to show him/her also his/her tags) // add the user (to show him also his own tags)
if(!is_null($logged_on_user)) { if (!is_null($logged_on_user)) {
$contacts[] = $logged_on_user; $contacts[] = $logged_on_user;
} }
// ask for their tags // 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. // Only count the tags that are visible to the current user.
if (($user != $logged_on_user) || is_null($user) || ($user === false)) if (($user != $logged_on_user) || is_null($user) || ($user === false)) {
$privacy = ' AND B.bStatus = 0'; $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 ';
if (is_null($user) || ($user === false)) {
$query .= 'B.bId = T.bId AND B.bStatus = 0';
} elseif(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';
}
$query .= ' )';
} else { } else {
$query .= 'B.uId = '. $this->db->sql_escape($user) .' AND B.bId = T.bId'. $privacy; $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))) { $query = 'SELECT'
message_die(GENERAL_ERROR, 'Could not get popular tags', '', __LINE__, __FILE__, $query, $this->db); . ' 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';
} else if (is_array($user)) {
$query .= ' (1 = 0'; //tricks
foreach ($user as $u) {
if (is_numeric($u)) {
$query .= ' OR B.uId = ' . $this->db->sql_escape($u)
. ' AND B.bId = T.bId';
}
}
$query .= ' )' . $privacy;
} else {
$query .= ' B.uId = ' . $this->db->sql_escape($user)
. ' AND B.bId = T.bId' . $privacy;
}
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; return false;
} }
@ -514,6 +611,8 @@ class SemanticScuttle_Service_Bookmark2Tag extends SemanticScuttle_DbService
return $output; return $output;
} }
function hasTag($bookmarkid, $tag) { function hasTag($bookmarkid, $tag) {
$query = 'SELECT COUNT(*) AS tCount FROM '. $this->getTableName() .' WHERE bId = '. intval($bookmarkid) .' AND tag ="'. $this->db->sql_escape($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; return $output;
} }
function deleteAll() {
/**
* Deletes all tags in bookmarks2tags
*
* @return void
*/
public function deleteAll()
{
$query = 'TRUNCATE TABLE `'. $this->getTableName() .'`'; $query = 'TRUNCATE TABLE `'. $this->getTableName() .'`';
$this->db->sql_query($query); $this->db->sql_query($query);
} }

View File

@ -26,7 +26,18 @@
*/ */
class SemanticScuttle_Service_SearchHistory extends SemanticScuttle_DbService 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 * Returns the single service instance
@ -44,109 +55,223 @@ class SemanticScuttle_Service_SearchHistory extends SemanticScuttle_DbService
return $instance; 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) public function __construct($db)
{ {
$this->db = $db; $this->db = $db;
$this->tablename = $GLOBALS['tableprefix'] .'searchhistory'; $this->tablename = $GLOBALS['tableprefix'] . 'searchhistory';
if(isset($GLOBALS['sizeSearchHistory'])) { if (isset($GLOBALS['sizeSearchHistory'])) {
$this->sizeSearchHistory = $GLOBALS['sizeSearchHistory']; $this->sizeSearchHistory = $GLOBALS['sizeSearchHistory'];
} else { } else {
$this->sizeSearchHistory = 10; $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; return false;
} }
$datetime = gmdate('Y-m-d H:i:s', time()); $datetime = gmdate('Y-m-d H:i:s', time());
//Insert values //Insert values
$values = array('shTerms'=>$terms, 'shRange'=>$range, 'shDatetime'=>$datetime, 'shNbResults'=>$nbResults, 'uId'=>$uId); $values = array(
$sql = 'INSERT INTO '. $this->getTableName() .' '. $this->db->sql_build_array('INSERT', $values); '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'); $this->db->sql_transaction('begin');
if (!($dbresult = & $this->db->sql_query($sql))) { if (!($dbresult = $this->db->sql_query($sql))) {
$this->db->sql_transaction('rollback'); $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; return false;
} }
if($this->sizeSearchHistory != -1 && if ($this->sizeSearchHistory != -1
$this->countSearches() > $this->sizeSearchHistory) { && $this->countSearches() > $this->sizeSearchHistory
) {
$this->deleteOldestSearch(); $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.= ' FROM '. $this->getTableName();
$sql.= ' WHERE 1=1'; $sql.= ' WHERE 1=1';
if($range != NULL) { if ($range != null) {
$sql.= ' AND shRange = "'.$range.'"'; $sql.= ' AND shRange = "'.$range.'"';
} else { } else {
$sql.= ' AND shRange = "all"'; $sql.= ' AND shRange = "all"';
} }
if($uId != NULL) { if ($uId != null) {
$sql.= ' AND uId = '.$uId; $sql.= ' AND uId = '.$uId;
} }
if($withResults = true) { if ($withResults == true) {
$sql.= ' AND shNbResults > 0'; $sql.= ' AND shNbResults > 0';
} }
if($distinct) { if ($distinct) {
$sql.= ' GROUP BY shTerms'; $sql.= ' GROUP BY shTerms';
} }
$sql.= ' ORDER BY shId DESC'; $sql.= ' ORDER BY shId DESC';
if (!($dbresult = & $this->db->sql_query_limit($sql, $nb, $start))) { if (!($dbresult = $this->db->sql_query_limit($sql, $nb, $start))) {
message_die(GENERAL_ERROR, 'Could not get searches', '', __LINE__, __FILE__, $sql, $this->db); message_die(
GENERAL_ERROR, 'Could not get searches',
'', __LINE__, __FILE__, $sql, $this->db
);
return false; return false;
} }
$searches = array(); $searches = array();
while ($row = & $this->db->sql_fetchrow($dbresult)) { while ($row = $this->db->sql_fetchrow($dbresult)) {
$searches[] = $row; $searches[] = $row;
} }
$this->db->sql_freeresult($dbresult); $this->db->sql_freeresult($dbresult);
return $searches; 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(); $sql = 'SELECT COUNT(*) AS `total` FROM '. $this->getTableName();
if (!($dbresult = & $this->db->sql_query($sql)) || (!($row = & $this->db->sql_fetchrow($dbresult)))) { if (!($dbresult = $this->db->sql_query($sql))
message_die(GENERAL_ERROR, 'Could not get total searches', '', __LINE__, __FILE__, $sql, $this->db); || (!($row = & $this->db->sql_fetchrow($dbresult)))
) {
message_die(
GENERAL_ERROR, 'Could not get total searches',
'', __LINE__, __FILE__, $sql, $this->db
);
return false; return false;
} }
$this->db->sql_freeresult($dbresult); $this->db->sql_freeresult($dbresult);
return $row['total']; 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 = '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'); $this->db->sql_transaction('begin');
if (!($dbresult = & $this->db->sql_query($sql))) { if (!($dbresult = $this->db->sql_query($sql))) {
$this->db->sql_transaction('rollback'); $this->db->sql_transaction('rollback');
message_die(GENERAL_ERROR, 'Could not delete bookmarks', '', __LINE__, __FILE__, $query, $this->db); message_die(
return false; GENERAL_ERROR, 'Could not delete bookmarks',
} '', __LINE__, __FILE__, $query, $this->db
} );
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 false;
} }
return true; return true;
} }
function deleteAll() {
/**
* 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;
}
/**
* Deletes all search history entries.
*
* @return void
*/
public function deleteAll()
{
$query = 'TRUNCATE TABLE `'. $this->getTableName() .'`'; $query = 'TRUNCATE TABLE `'. $this->getTableName() .'`';
$this->db->sql_query($query); $this->db->sql_query($query);
} }

View File

@ -14,7 +14,7 @@
*/ */
/** /**
* SemanticScuttle tag-to-tag service. * SemanticScuttle tag-to-tag service which works with tag relations.
* *
* @category Bookmarking * @category Bookmarking
* @package SemanticScuttle * @package SemanticScuttle
@ -102,18 +102,49 @@ class SemanticScuttle_Service_Tag2Tag extends SemanticScuttle_DbService
return true; 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 // look for admin ids
$userservice = SemanticScuttle_Service_Factory :: get('User'); $userservice = SemanticScuttle_Service_Factory :: get('User');
$adminIds = $userservice->getAdminIds(); $adminIds = $userservice->getAdminIds();
//ask for their linked tags //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. // Set up the SQL query.
if($inverseRelation) { if($inverseRelation) {
$queriedTag = "tag1"; $queriedTag = "tag1";

View File

@ -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 */ * Obtains the ID of the given user name.
function getIdFromUser($user) { * 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)) { if (is_int($user)) {
return intval($user); return intval($user);
} else { } else {
$objectUser = $this->getObjectUserByUsername($user); $objectUser = $this->getObjectUserByUsername($user);
if($objectUser != NULL) { if ($objectUser != null) {
return $objectUser->getId(); return $objectUser->getId();
} }
} }
return NULL; return null;
} }
/** /**
@ -404,10 +412,10 @@ class SemanticScuttle_Service_User extends SemanticScuttle_DbService
public function getCurrentUserId() public function getCurrentUserId()
{ {
if (isset($_SESSION[$this->getSessionKey()])) { if (isset($_SESSION[$this->getSessionKey()])) {
return $_SESSION[$this->getSessionKey()]; return (int)$_SESSION[$this->getSessionKey()];
} else if (isset($_COOKIE[$this->getCookieKey()])) { } else if (isset($_COOKIE[$this->getCookieKey()])) {
$cook = split(':', $_COOKIE[$this->getCookieKey()]); $cook = explode(':', $_COOKIE[$this->getCookieKey()]);
//cookie looks like this: 'id:md5(username+password)' //cookie looks like this: 'id:md5(username+password)'
$query = 'SELECT * FROM '. $this->getTableName() . $query = 'SELECT * FROM '. $this->getTableName() .
' WHERE MD5(CONCAT('.$this->getFieldName('username') . ' WHERE MD5(CONCAT('.$this->getFieldName('username') .
@ -425,10 +433,10 @@ class SemanticScuttle_Service_User extends SemanticScuttle_DbService
if ($row = $this->db->sql_fetchrow($dbresult)) { if ($row = $this->db->sql_fetchrow($dbresult)) {
$this->setCurrentUserId( $this->setCurrentUserId(
$row[$this->getFieldName('primary')] (int)$row[$this->getFieldName('primary')]
); );
$this->db->sql_freeresult($dbresult); $this->db->sql_freeresult($dbresult);
return $_SESSION[$this->getSessionKey()]; return (int)$_SESSION[$this->getSessionKey()];
} }
} }
return false; 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. * Mainly used in unit tests.
* *
* @return void * @return void
@ -725,6 +733,9 @@ class SemanticScuttle_Service_User extends SemanticScuttle_DbService
{ {
$query = 'TRUNCATE TABLE `'. $this->getTableName() .'`'; $query = 'TRUNCATE TABLE `'. $this->getTableName() .'`';
$this->db->sql_query($query); $this->db->sql_query($query);
$query = 'TRUNCATE TABLE `' . $GLOBALS['tableprefix'] . 'watched' . '`';
$this->db->sql_query($query);
} }
/** /**

View File

@ -1,13 +1,27 @@
<?php <?php
/* /**
* Define constants used in all the application. * Define constants used in all the application.
* Some constants are based on variables from configuration file. * 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 // Debug managament
if(isset($GLOBALS['debugMode'])) { if (isset($GLOBALS['debugMode'])) {
define('DEBUG_MODE', $GLOBALS['debugMode']); define('DEBUG_MODE', $GLOBALS['debugMode']);
define('DEBUG_EXTRA', $GLOBALS['debugMode']); // Constant used exclusively into db/ directory // Constant used exclusively into db/ directory
define('DEBUG_EXTRA', $GLOBALS['debugMode']);
} }
// Determine the base URL as ROOT // Determine the base URL as ROOT
@ -17,7 +31,9 @@ if (!isset($GLOBALS['root'])) {
$rootTmp = '/'; $rootTmp = '/';
foreach ($pieces as $piece) { foreach ($pieces as $piece) {
//we eliminate possible sscuttle subfolders (like gsearch for example) //we eliminate possible sscuttle subfolders (like gsearch for example)
if ($piece != '' && !strstr($piece, '.php') && $piece != 'gsearch') { if ($piece != '' && !strstr($piece, '.php')
&& $piece != 'gsearch' && $piece != 'ajax'
) {
$rootTmp .= $piece .'/'; $rootTmp .= $piece .'/';
} }
} }
@ -29,6 +45,7 @@ if (!isset($GLOBALS['root'])) {
} else { } else {
define('ROOT', $GLOBALS['root']); define('ROOT', $GLOBALS['root']);
} }
define('ROOT_JS', ROOT . 'js/jstree-1.0-rc2/');
// Error codes // Error codes
define('GENERAL_MESSAGE', 200); define('GENERAL_MESSAGE', 200);
@ -44,18 +61,20 @@ define('PAGE_WATCHLIST', "watchlist");
// Miscellanous // 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'])); define('INSTALLATION_ID', md5($GLOBALS['dbname'].$GLOBALS['tableprefix']));
// Correct bugs with PATH_INFO (maybe for Apache 1 or CGI) -- for 1&1 host... // 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 (isset($_SERVER['PATH_INFO']) && isset($_SERVER['ORIG_PATH_INFO'])) {
if(strlen($_SERVER["PATH_INFO"])<strlen($_SERVER["ORIG_PATH_INFO"])) { if (strlen($_SERVER["PATH_INFO"])<strlen($_SERVER["ORIG_PATH_INFO"])) {
$_SERVER["PATH_INFO"] = $_SERVER["ORIG_PATH_INFO"]; $_SERVER["PATH_INFO"] = $_SERVER["ORIG_PATH_INFO"];
} }
if(strcasecmp($_SERVER["PATH_INFO"], $_SERVER["SCRIPT_NAME "]) == 0) { if (strcasecmp($_SERVER["PATH_INFO"], $_SERVER["SCRIPT_NAME "]) == 0) {
unset($_SERVER["PATH_INFO"]); unset($_SERVER["PATH_INFO"]);
} }
if(strpos($_SERVER["PATH_INFO"], '.php') !== false) { if (strpos($_SERVER["PATH_INFO"], '.php') !== false) {
unset($_SERVER["PATH_INFO"]); unset($_SERVER["PATH_INFO"]);
} }
} }

View File

@ -50,7 +50,7 @@ class sql_db
} }
} }
return $this->sql_error(''); return $this->sql_error(mysqli_connect_error());
} }
// //

View File

@ -14,9 +14,21 @@
* @license GPL http://www.gnu.org/licenses/gpl.html * @license GPL http://www.gnu.org/licenses/gpl.html
* @link http://sourceforge.net/projects/semanticscuttle * @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'); 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( set_include_path(
get_include_path() . PATH_SEPARATOR get_include_path() . PATH_SEPARATOR
@ -24,10 +36,23 @@ set_include_path(
); );
// 1 // First requirements part (before debug management) // 1 // First requirements part (before debug management)
$datadir = dirname(__FILE__) . '/../../data/';
require_once $datadir . '/config.default.php'; require_once $datadir . '/config.default.php';
require_once $datadir . '/config.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')) { if (defined('UNIT_TEST_MODE')) {
//make local config vars global - needed for unit tests //make local config vars global - needed for unit tests
//run with phpunit //run with phpunit
@ -57,6 +82,7 @@ require_once 'SemanticScuttle/Service.php';
require_once 'SemanticScuttle/DbService.php'; require_once 'SemanticScuttle/DbService.php';
require_once 'SemanticScuttle/Service/Factory.php'; require_once 'SemanticScuttle/Service/Factory.php';
require_once 'SemanticScuttle/functions.php'; require_once 'SemanticScuttle/functions.php';
require_once 'SemanticScuttle/Model/UserArray.php';
if (count($GLOBALS['serviceoverrides']) > 0 if (count($GLOBALS['serviceoverrides']) > 0
&& !defined('UNIT_TEST_MODE') && !defined('UNIT_TEST_MODE')
@ -106,11 +132,18 @@ $tplVars['currentUser'] = $currentUser;
$tplVars['userservice'] = $userservice; $tplVars['userservice'] = $userservice;
// 6 // Force UTF-8 behaviour for server (cannot be moved into top.inc.php which is not included into every file) // 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 //API files define that, so we need a way to support both of them
if (!isset($httpContentType)) { if (!isset($httpContentType)) {
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'; $httpContentType = 'text/html';
//$httpContentType = 'application/xhtml+xml'; }
} }
if ($httpContentType !== false) { if ($httpContentType !== false) {
header('Content-Type: ' . $httpContentType . '; charset=utf-8'); header('Content-Type: ' . $httpContentType . '; charset=utf-8');

View File

@ -1,12 +1,11 @@
PACKAGE = php-gettext-$(VERSION) PACKAGE = php-gettext-$(VERSION)
VERSION = 1.0.7 VERSION = 1.0.10
DIST_FILES = \ DIST_FILES = \
gettext.php \ gettext.php \
gettext.inc \ gettext.inc \
streams.php \ streams.php \
AUTHORS \ AUTHORS \
ChangeLog \
README \ README \
COPYING \ COPYING \
Makefile \ Makefile \
@ -17,9 +16,14 @@ DIST_FILES = \
examples/locale/sr_CS/LC_MESSAGES/messages.mo \ examples/locale/sr_CS/LC_MESSAGES/messages.mo \
examples/locale/de_CH/LC_MESSAGES/messages.po \ examples/locale/de_CH/LC_MESSAGES/messages.po \
examples/locale/de_CH/LC_MESSAGES/messages.mo \ 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 \ if [ -d $(PACKAGE) ]; then \
rm -rf $(PACKAGE); \ rm -rf $(PACKAGE); \
fi; \ fi; \
@ -30,3 +34,5 @@ dist:
rm -rf $(PACKAGE); \ rm -rf $(PACKAGE); \
fi; fi;
clean:
rm -f $(PACKAGE).tar.gz

View File

@ -1,6 +1,6 @@
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) 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
@ -59,27 +59,7 @@ Features
Bugs Bugs
Plural-forms field in MO header (translation for empty string, Report them on https://bugs.launchpad.net/php-gettext
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.
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>.
Usage Usage
@ -137,18 +117,10 @@ Example
There is also simple "update" script that can be used to generate There is also simple "update" script that can be used to generate
POT file and to update the translation using msgmerge. 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 o Improve speed to be even more comparable to the native gettext
rules. This won't be easy. 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? be useful at all?

View File

@ -12,7 +12,8 @@ msgstr ""
"MIME-Version: 1.0\n" "MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n" "Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\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 #: pigs.php:19
msgid "" msgid ""

View File

@ -1,6 +1,6 @@
<?php <?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> Copyright (c) 2005,2006 Steven Armstrong <sa@c-area.ch>
This file is part of PHP-gettext. This file is part of PHP-gettext.
@ -21,10 +21,12 @@
*/ */
error_reporting(E_ALL | E_STRICT);
// define constants // define constants
define(PROJECT_DIR, realpath('./')); define('PROJECT_DIR', realpath('./'));
define(LOCALE_DIR, PROJECT_DIR .'/locale'); define('LOCALE_DIR', PROJECT_DIR .'/locale');
define(DEFAULT_LOCALE, 'en_US'); define('DEFAULT_LOCALE', 'en_US');
require_once('../gettext.inc'); require_once('../gettext.inc');

View File

@ -1,6 +1,6 @@
<?php <?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> Copyright (c) 2005,2006 Steven Armstrong <sa@c-area.ch>
This file is part of PHP-gettext. This file is part of PHP-gettext.
@ -21,10 +21,12 @@
*/ */
error_reporting(E_ALL | E_STRICT);
// define constants // define constants
define(PROJECT_DIR, realpath('./')); define('PROJECT_DIR', realpath('./'));
define(LOCALE_DIR, PROJECT_DIR .'/locale'); define('LOCALE_DIR', PROJECT_DIR .'/locale');
define(DEFAULT_LOCALE, 'en_US'); define('DEFAULT_LOCALE', 'en_US');
require_once('../gettext.inc'); require_once('../gettext.inc');

View File

@ -1,7 +1,7 @@
#!/bin/sh #!/bin/sh
TEMPLATE=pigs.pot TEMPLATE=pigs.pot
xgettext -kT_ngettext:1,2 -kT_ -L PHP -o $TEMPLATE pigs.php xgettext -kT_ngettext:1,2 -kT_ -L PHP -o $TEMPLATE pigs_dropin.php
if [ x$1 == 'x-p' ]; then if [ "x$1" = "x-p" ]; then
msgfmt --statistics $TEMPLATE msgfmt --statistics $TEMPLATE
else else
if [ -f $1.po ]; then if [ -f $1.po ]; then

View File

@ -1,6 +1,7 @@
<?php <?php
/* /*
Copyright (c) 2005 Steven Armstrong <sa at c-area dot ch> 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. Drop in replacement for native gettext.
@ -31,6 +32,13 @@ LC_MESSAGES 5
LC_ALL 6 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('streams.php');
require('gettext.php'); require('gettext.php');
@ -44,9 +52,65 @@ $LC_CATEGORIES = array('LC_CTYPE', 'LC_NUMERIC', 'LC_TIME', 'LC_COLLATE', 'LC_MO
$EMULATEGETTEXT = 0; $EMULATEGETTEXT = 0;
$CURRENTLOCALE = ''; $CURRENTLOCALE = '';
/* Class to hold a single domain included in $text_domains. */
class domain {
var $l10n;
var $path;
var $codeset;
}
// Utility functions // 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. * Utility function to get a StreamReader for the given text domain.
*/ */
@ -56,15 +120,26 @@ function _get_reader($domain=null, $category=5, $enable_cache=true) {
if (!isset($text_domains[$domain]->l10n)) { if (!isset($text_domains[$domain]->l10n)) {
// get the current locale // get the current locale
$locale = _setlocale(LC_MESSAGES, 0); $locale = _setlocale(LC_MESSAGES, 0);
$p = isset($text_domains[$domain]->path) ? $text_domains[$domain]->path : './'; $bound_path = isset($text_domains[$domain]->path) ?
$path = $p . "$locale/". $LC_CATEGORIES[$category] ."/$domain.mo"; $text_domains[$domain]->path : './';
if (file_exists($path)) { $subpath = $LC_CATEGORIES[$category] ."/$domain.mo";
$input = new FileReader($path);
} $locale_names = get_list_of_locales($locale);
else {
$input = null; $input = null;
foreach ($locale_names as $locale) {
$full_path = $bound_path . $locale . "/" . $subpath;
if (file_exists($full_path)) {
$input = new FileReader($full_path);
break;
} }
$text_domains[$domain]->l10n = new gettext_reader($input, $enable_cache); }
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; return $text_domains[$domain]->l10n;
} }
@ -80,8 +155,10 @@ function locale_emulation() {
/** /**
* Checks if the current locale is supported on this system. * Checks if the current locale is supported on this system.
*/ */
function _check_locale() { function _check_locale_and_function($function=false) {
global $EMULATEGETTEXT; global $EMULATEGETTEXT;
if ($function and !function_exists($function))
return false;
return !$EMULATEGETTEXT; return !$EMULATEGETTEXT;
} }
@ -109,10 +186,18 @@ function _encode($text) {
} }
// Custom implementation of the standard gettext related functions // 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. * Sets a requested locale, if needed emulates it.
*/ */
@ -126,19 +211,25 @@ function _setlocale($category, $locale) {
// even if we tried to read locale without setting it first // even if we tried to read locale without setting it first
return _setlocale($category, $CURRENTLOCALE); return _setlocale($category, $CURRENTLOCALE);
} else { } else {
$ret = 0; if (function_exists('setlocale')) {
if (function_exists('setlocale')) // I don't know if this ever happens ;) $ret = setlocale($category, $locale);
$ret = @setlocale($category, $locale); //the @ hides warning messages on few installations if (($locale == '' and !$ret) or // failed setting it by env
if (($ret and $locale == '') or ($ret == $locale)) { ($locale != '' and $ret != $locale)) { // failed setting it
$EMULATEGETTEXT = 0; // Failed setting it according to environment.
$CURRENTLOCALE = $ret; $CURRENTLOCALE = _get_default_locale($locale);
$EMULATEGETTEXT = 1;
} else { } else {
if ($locale == '') // emulate variable support $CURRENTLOCALE = $ret;
$CURRENTLOCALE = getenv('LANG'); $EMULATEGETTEXT = 0;
else }
$CURRENTLOCALE = $locale; } else {
// No function setlocale(), emulate it all.
$CURRENTLOCALE = _get_default_locale($locale);
$EMULATEGETTEXT = 1; $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; return $CURRENTLOCALE;
} }
} }
@ -148,9 +239,18 @@ function _setlocale($category, $locale) {
*/ */
function _bindtextdomain($domain, $path) { function _bindtextdomain($domain, $path) {
global $text_domains; global $text_domains;
// ensure $path ends with a slash // ensure $path ends with a slash ('/' should work for both, but lets still play nice)
if ($path[strlen($path) - 1] != '/') $path .= '/'; if (substr(php_uname(), 0, 7) == "Windows") {
elseif ($path[strlen($path) - 1] != '\\') $path .= '\\'; 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; $text_domains[$domain]->path = $path;
} }
@ -175,21 +275,21 @@ function _textdomain($domain) {
*/ */
function _gettext($msgid) { function _gettext($msgid) {
$l10n = _get_reader(); $l10n = _get_reader();
//return $l10n->translate($msgid);
return _encode($l10n->translate($msgid)); return _encode($l10n->translate($msgid));
} }
/** /**
* Alias for gettext. * Alias for gettext.
*/ */
function __($msgid) { function __($msgid) {
return _gettext($msgid); return _gettext($msgid);
} }
/** /**
* Plural version of gettext. * Plural version of gettext.
*/ */
function _ngettext($single, $plural, $number) { function _ngettext($single, $plural, $number) {
$l10n = _get_reader(); $l10n = _get_reader();
//return $l10n->ngettext($single, $plural, $number);
return _encode($l10n->ngettext($single, $plural, $number)); return _encode($l10n->ngettext($single, $plural, $number));
} }
@ -198,15 +298,14 @@ function _ngettext($single, $plural, $number) {
*/ */
function _dgettext($domain, $msgid) { function _dgettext($domain, $msgid) {
$l10n = _get_reader($domain); $l10n = _get_reader($domain);
//return $l10n->translate($msgid);
return _encode($l10n->translate($msgid)); return _encode($l10n->translate($msgid));
} }
/** /**
* Plural version of dgettext. * Plural version of dgettext.
*/ */
function _dngettext($domain, $single, $plural, $number) { function _dngettext($domain, $single, $plural, $number) {
$l10n = _get_reader($domain); $l10n = _get_reader($domain);
//return $l10n->ngettext($single, $plural, $number);
return _encode($l10n->ngettext($single, $plural, $number)); return _encode($l10n->ngettext($single, $plural, $number));
} }
@ -215,7 +314,6 @@ function _dngettext($domain, $single, $plural, $number) {
*/ */
function _dcgettext($domain, $msgid, $category) { function _dcgettext($domain, $msgid, $category) {
$l10n = _get_reader($domain, $category); $l10n = _get_reader($domain, $category);
//return $l10n->translate($msgid);
return _encode($l10n->translate($msgid)); return _encode($l10n->translate($msgid));
} }
/** /**
@ -223,61 +321,159 @@ function _dcgettext($domain, $msgid, $category) {
*/ */
function _dcngettext($domain, $single, $plural, $number, $category) { function _dcngettext($domain, $single, $plural, $number, $category) {
$l10n = _get_reader($domain, $category); $l10n = _get_reader($domain, $category);
//return $l10n->ngettext($single, $plural, $number);
return _encode($l10n->ngettext($single, $plural, $number)); 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. // Wrappers to use if the standard gettext functions are available,
// Use the standard impl if the current locale is supported, use the custom impl otherwise. // 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) { function T_setlocale($category, $locale) {
return _setlocale($category, $locale); return _setlocale($category, $locale);
} }
function T_bindtextdomain($domain, $path) { function T_bindtextdomain($domain, $path) {
if (_check_locale()) return bindtextdomain($domain, $path); if (_check_locale_and_function()) return bindtextdomain($domain, $path);
else return _bindtextdomain($domain, $path); else return _bindtextdomain($domain, $path);
} }
function T_bind_textdomain_codeset($domain, $codeset) { function T_bind_textdomain_codeset($domain, $codeset) {
// bind_textdomain_codeset is available only in PHP 4.2.0+ // 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); if (_check_locale_and_function('bind_textdomain_codeset'))
return bind_textdomain_codeset($domain, $codeset);
else return _bind_textdomain_codeset($domain, $codeset); else return _bind_textdomain_codeset($domain, $codeset);
} }
function T_textdomain($domain) { function T_textdomain($domain) {
if (_check_locale()) return textdomain($domain); if (_check_locale_and_function()) return textdomain($domain);
else return _textdomain($domain); else return _textdomain($domain);
} }
function T_gettext($msgid) { function T_gettext($msgid) {
if (_check_locale()) return gettext($msgid); if (_check_locale_and_function()) return gettext($msgid);
else return _gettext($msgid); else return _gettext($msgid);
} }
function T_($msgid) { function T_($msgid) {
if (_check_locale()) return _($msgid); if (_check_locale_and_function()) return _($msgid);
return __($msgid); return __($msgid);
} }
function T_ngettext($single, $plural, $number) { function T_ngettext($single, $plural, $number) {
if (_check_locale()) return ngettext($single, $plural, $number); if (_check_locale_and_function())
return ngettext($single, $plural, $number);
else return _ngettext($single, $plural, $number); else return _ngettext($single, $plural, $number);
} }
function T_dgettext($domain, $msgid) { function T_dgettext($domain, $msgid) {
if (_check_locale()) return dgettext($domain, $msgid); if (_check_locale_and_function()) return dgettext($domain, $msgid);
else return _dgettext($domain, $msgid); else return _dgettext($domain, $msgid);
} }
function T_dngettext($domain, $single, $plural, $number) { function T_dngettext($domain, $single, $plural, $number) {
if (_check_locale()) return dngettext($domain, $single, $plural, $number); if (_check_locale_and_function())
return dngettext($domain, $single, $plural, $number);
else return _dngettext($domain, $single, $plural, $number); else return _dngettext($domain, $single, $plural, $number);
} }
function T_dcgettext($domain, $msgid, $category) { function T_dcgettext($domain, $msgid, $category) {
if (_check_locale()) return dcgettext($domain, $msgid, $category); if (_check_locale_and_function())
return dcgettext($domain, $msgid, $category);
else return _dcgettext($domain, $msgid, $category); else return _dcgettext($domain, $msgid, $category);
} }
function T_dcngettext($domain, $single, $plural, $number, $category) { function T_dcngettext($domain, $single, $plural, $number, $category) {
if (_check_locale()) 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); 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);
}
// Wrappers used as a drop in replacement for the standard gettext functions // Wrappers used as a drop in replacement for the standard gettext functions
@ -313,6 +509,26 @@ if (!function_exists('gettext')) {
function dcngettext($domain, $single, $plural, $number, $category) { function dcngettext($domain, $single, $plural, $number, $category) {
return _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);
}
} }
?> ?>

View File

@ -1,6 +1,6 @@
<?php <?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> Copyright (c) 2005 Nico Kaiser <nico@siriux.net>
This file is part of PHP-gettext. This file is part of PHP-gettext.
@ -63,13 +63,19 @@ class gettext_reader {
function readint() { function readint() {
if ($this->BYTEORDER == 0) { if ($this->BYTEORDER == 0) {
// low endian // low endian
return array_shift(unpack('V', $this->STREAM->read(4))); $input=unpack('V', $this->STREAM->read(4));
return array_shift($input);
} else { } else {
// big endian // 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 * Reads an array of Integers from the Stream
* *
@ -102,17 +108,15 @@ class gettext_reader {
// Caching can be turned off // Caching can be turned off
$this->enable_cache = $enable_cache; $this->enable_cache = $enable_cache;
// $MAGIC1 = (int)0x950412de; //bug in PHP 5 $MAGIC1 = "\x95\x04\x12\xde";
$MAGIC1 = (int) - 1794895138; $MAGIC2 = "\xde\x12\x04\x95";
// $MAGIC2 = (int)0xde120495; //bug
$MAGIC2 = (int) - 569244523;
$this->STREAM = $Reader; $this->STREAM = $Reader;
$magic = $this->readint(); $magic = $this->read(4);
if ($magic == $MAGIC1 || $magic == ($MAGIC1 & 0xFFFFFFFF)) { if ($magic == $MAGIC1) {
$this->BYTEORDER = 0;
} elseif ($magic == $MAGIC2 || $magic == ($MAGIC2 & 0xFFFFFFFF)) {
$this->BYTEORDER = 1; $this->BYTEORDER = 1;
} elseif ($magic == $MAGIC2) {
$this->BYTEORDER = 0;
} else { } else {
$this->error = 1; // not MO file $this->error = 1; // not MO file
return false; return false;
@ -140,10 +144,14 @@ class gettext_reader {
return; return;
/* get original and translations tables */ /* get original and translations tables */
if (!is_array($this->table_originals)) {
$this->STREAM->seekto($this->originals); $this->STREAM->seekto($this->originals);
$this->table_originals = $this->readintarray($this->total * 2); $this->table_originals = $this->readintarray($this->total * 2);
}
if (!is_array($this->table_translations)) {
$this->STREAM->seekto($this->translations); $this->STREAM->seekto($this->translations);
$this->table_translations = $this->readintarray($this->total * 2); $this->table_translations = $this->readintarray($this->total * 2);
}
if ($this->enable_cache) { if ($this->enable_cache) {
$this->cache_translations = array (); $this->cache_translations = array ();
@ -261,6 +269,55 @@ 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 * Get possible plural forms from MO header
* *
@ -279,11 +336,8 @@ class gettext_reader {
} else { } else {
$header = $this->get_translation_string(0); $header = $this->get_translation_string(0);
} }
if (eregi("plural-forms: ([^\n]*)\n", $header, $regs)) $expr = $this->extract_plural_forms_header_from_po_header($header);
$expr = $regs[1]; $this->pluralheader = $this->sanitize_plural_expression($expr);
else
$expr = "nplurals=2; plural=n == 1 ? 0 : 1;";
$this->pluralheader = $expr;
} }
return $this->pluralheader; return $this->pluralheader;
} }
@ -330,7 +384,7 @@ class gettext_reader {
$select = $this->select_string($number); $select = $this->select_string($number);
// this should contains all strings separated by NULLs // this should contains all strings separated by NULLs
$key = $single.chr(0).$plural; $key = $single . chr(0) . $plural;
if ($this->enable_cache) { if ($this->enable_cache) {
@ -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);
}
} }
?> ?>

View File

@ -1,6 +1,6 @@
<?php <?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. This file is part of PHP-gettext.
@ -21,8 +21,8 @@
*/ */
// Simple class to wrap file streams, string streams, etc. // Simple class to wrap file streams, string streams, etc.
// seek is essential, and it should be byte stream // seek is essential, and it should be byte stream
class StreamReader { class StreamReader {
// should return a string [FIXME: perhaps return array of bytes?] // should return a string [FIXME: perhaps return array of bytes?]
function read($bytes) { function read($bytes) {
@ -43,7 +43,7 @@ class StreamReader {
function length() { function length() {
return false; return false;
} }
} };
class StringReader { class StringReader {
var $_pos; var $_pos;
@ -78,7 +78,7 @@ class StringReader {
return strlen($this->_str); return strlen($this->_str);
} }
} };
class FileReader { class FileReader {
@ -138,7 +138,7 @@ class FileReader {
fclose($this->_fd); 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) // over it (it assumes knowledge of StringReader internals)
@ -161,7 +161,7 @@ class CachedFileReader extends StringReader {
return false; return false;
} }
} }
} };
?> ?>

View File

@ -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(""));
}
}
?>

View File

@ -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"
));
}
}
?>

View File

@ -17,9 +17,6 @@ if (!defined('PHPUnit_MAIN_METHOD')) {
} }
require_once 'prepare.php'; require_once 'prepare.php';
require_once 'PHPUnit/Framework/TestSuite.php';
PHPUnit_Util_Filter::addFileToFilter(__FILE__);
/** /**
* SemanticScuttle unit tests. * SemanticScuttle unit tests.
@ -64,6 +61,10 @@ class AllTests extends PHPUnit_Framework_TestSuite
$suite->addTestFile($tdir . '/TagTest.php'); $suite->addTestFile($tdir . '/TagTest.php');
$suite->addTestFile($tdir . '/VoteTest.php'); $suite->addTestFile($tdir . '/VoteTest.php');
$suite->addTestFile($tdir . '/UserTest.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; return $suite;
} }

435
tests/Api/PostsAddTest.php Normal file
View File

@ -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();
}
?>

View File

@ -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();
}
?>

View File

@ -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();
}
?>

View File

@ -12,13 +12,12 @@
* @license GPL http://www.gnu.org/licenses/gpl.html * @license GPL http://www.gnu.org/licenses/gpl.html
* @link http://sourceforge.net/projects/semanticscuttle * @link http://sourceforge.net/projects/semanticscuttle
*/ */
require_once 'prepare.php';
if (!defined('PHPUnit_MAIN_METHOD')) { if (!defined('PHPUnit_MAIN_METHOD')) {
define('PHPUnit_MAIN_METHOD', 'Bookmark2TagTest::main'); define('PHPUnit_MAIN_METHOD', 'Bookmark2TagTest::main');
} }
require_once 'prepare.php';
/** /**
* Unit tests for the SemanticScuttle bookmark-tag combination service. * Unit tests for the SemanticScuttle bookmark-tag combination service.
* *
@ -38,6 +37,26 @@ class Bookmark2TagTest extends TestBase
protected $tts; 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 * Used to run this test class standalone
@ -57,6 +76,7 @@ class Bookmark2TagTest extends TestBase
protected function setUp() protected function setUp()
{ {
$this->us = SemanticScuttle_Service_Factory::get('User'); $this->us = SemanticScuttle_Service_Factory::get('User');
$this->us->deleteAll();
$this->bs = SemanticScuttle_Service_Factory::get('Bookmark'); $this->bs = SemanticScuttle_Service_Factory::get('Bookmark');
$this->bs->deleteAll(); $this->bs->deleteAll();
$this->b2ts= SemanticScuttle_Service_Factory::get('Bookmark2Tag'); $this->b2ts= SemanticScuttle_Service_Factory::get('Bookmark2Tag');
@ -74,7 +94,7 @@ class Bookmark2TagTest extends TestBase
/** /**
* Test getTagsForBookmark() when the bookmark has no tags * Test getTagsForBookmark() when the bookmark has no tags
* *
* @return void * @covers SemanticScuttle_Service_Bookmark2Tag::getTagsForBookmark
*/ */
public function testGetTagsForBookmarkNone() public function testGetTagsForBookmarkNone()
{ {
@ -92,7 +112,7 @@ class Bookmark2TagTest extends TestBase
/** /**
* Test getTagsForBookmark() when the bookmark has one tag * Test getTagsForBookmark() when the bookmark has one tag
* *
* @return void * @covers SemanticScuttle_Service_Bookmark2Tag::getTagsForBookmark
*/ */
public function testGetTagsForBookmarkOne() public function testGetTagsForBookmarkOne()
{ {
@ -111,9 +131,9 @@ class Bookmark2TagTest extends TestBase
/** /**
* Test getTagsForBookmark() when the bookmark has three tags * 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')); $this->addBookmark(null, null, 0, array('forz', 'barz'));
@ -121,7 +141,7 @@ class Bookmark2TagTest extends TestBase
$this->b2ts->attachTags($bid, array('foo', 'bar', 'fuu')); $this->b2ts->attachTags($bid, array('foo', 'bar', 'fuu'));
$tags = $this->b2ts->getTagsForBookmark($bid); $tags = $this->b2ts->getTagsForBookmark($bid);
$this->assertType('array', $tags); $this->assertInternalType('array', $tags);
$this->assertContains('foo', $tags); $this->assertContains('foo', $tags);
$this->assertContains('bar', $tags); $this->assertContains('bar', $tags);
$this->assertContains('fuu', $tags); $this->assertContains('fuu', $tags);
@ -132,7 +152,7 @@ class Bookmark2TagTest extends TestBase
/** /**
* Test getTagsForBookmarks() when no bookmarks have tags. * Test getTagsForBookmarks() when no bookmarks have tags.
* *
* @return void * @covers SemanticScuttle_Service_Bookmark2Tag::getTagsForBookmarks
*/ */
public function testGetTagsForBookmarksNone() public function testGetTagsForBookmarksNone()
{ {
@ -142,10 +162,10 @@ class Bookmark2TagTest extends TestBase
$alltags = $this->b2ts->getTagsForBookmarks( $alltags = $this->b2ts->getTagsForBookmarks(
array($bid1, $bid2) array($bid1, $bid2)
); );
$this->assertType('array', $alltags); $this->assertInternalType('array', $alltags);
$this->assertEquals(2, count($alltags)); $this->assertEquals(2, count($alltags));
$this->assertType('array', $alltags[$bid1]); $this->assertInternalType('array', $alltags[$bid1]);
$this->assertType('array', $alltags[$bid2]); $this->assertInternalType('array', $alltags[$bid2]);
$this->assertEquals(0, count($alltags[$bid1])); $this->assertEquals(0, count($alltags[$bid1]));
$this->assertEquals(0, count($alltags[$bid2])); $this->assertEquals(0, count($alltags[$bid2]));
} }
@ -155,7 +175,7 @@ class Bookmark2TagTest extends TestBase
/** /**
* Test getTagsForBookmarks() when most bookmarks have tags. * Test getTagsForBookmarks() when most bookmarks have tags.
* *
* @return void * @covers SemanticScuttle_Service_Bookmark2Tag::getTagsForBookmarks
*/ */
public function testGetTagsForBookmarksMost() public function testGetTagsForBookmarksMost()
{ {
@ -180,9 +200,9 @@ class Bookmark2TagTest extends TestBase
$alltags = $this->b2ts->getTagsForBookmarks( $alltags = $this->b2ts->getTagsForBookmarks(
array($bid1, $bid2, $bid3, $bid4) array($bid1, $bid2, $bid3, $bid4)
); );
$this->assertType('array', $alltags); $this->assertInternalType('array', $alltags);
foreach ($alltags as $bid => $btags) { foreach ($alltags as $bid => $btags) {
$this->assertType('array', $btags); $this->assertInternalType('array', $btags);
if ($bid == $bid1) { if ($bid == $bid1) {
$this->assertEquals(3, count($btags)); $this->assertEquals(3, count($btags));
$this->assertContains('foo', $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') { if (PHPUnit_MAIN_METHOD == 'Bookmark2TagTest::main') {

View File

@ -12,13 +12,12 @@
* @license GPL http://www.gnu.org/licenses/gpl.html * @license GPL http://www.gnu.org/licenses/gpl.html
* @link http://sourceforge.net/projects/semanticscuttle * @link http://sourceforge.net/projects/semanticscuttle
*/ */
require_once 'prepare.php';
if (!defined('PHPUnit_MAIN_METHOD')) { if (!defined('PHPUnit_MAIN_METHOD')) {
define('PHPUnit_MAIN_METHOD', 'BookmarkTest::main'); define('PHPUnit_MAIN_METHOD', 'BookmarkTest::main');
} }
require_once 'prepare.php';
/** /**
* Unit tests for the SemanticScuttle bookmark service. * Unit tests for the SemanticScuttle bookmark service.
* *
@ -264,7 +263,7 @@ class BookmarkTest extends TestBase
$bookmark = $this->bs->getBookmark($bid); $bookmark = $this->bs->getBookmark($bid);
$ret = $this->bs->bookmarksExist(array($bookmark['bAddress'])); $ret = $this->bs->bookmarksExist(array($bookmark['bAddress']));
$this->assertType('array', $ret); $this->assertInternalType('array', $ret);
$this->assertEquals(1, count($ret)); $this->assertEquals(1, count($ret));
$this->assertTrue($ret[$bookmark['bAddress']]); $this->assertTrue($ret[$bookmark['bAddress']]);
} }
@ -292,7 +291,7 @@ class BookmarkTest extends TestBase
$bookmark2['bAddress'] $bookmark2['bAddress']
) )
); );
$this->assertType('array', $ret); $this->assertInternalType('array', $ret);
$this->assertEquals(2, count($ret)); $this->assertEquals(2, count($ret));
$this->assertTrue($ret[$bookmark['bAddress']]); $this->assertTrue($ret[$bookmark['bAddress']]);
$this->assertTrue($ret[$bookmark2['bAddress']]); $this->assertTrue($ret[$bookmark2['bAddress']]);
@ -309,7 +308,7 @@ class BookmarkTest extends TestBase
public function testBookmarksExistFalseSingle() public function testBookmarksExistFalseSingle()
{ {
$ret = $this->bs->bookmarksExist(array('does-not-exist')); $ret = $this->bs->bookmarksExist(array('does-not-exist'));
$this->assertType('array', $ret); $this->assertInternalType('array', $ret);
$this->assertEquals(1, count($ret)); $this->assertEquals(1, count($ret));
$this->assertFalse($ret['does-not-exist']); $this->assertFalse($ret['does-not-exist']);
} }
@ -330,7 +329,7 @@ class BookmarkTest extends TestBase
'does-not-exist-3', 'does-not-exist-3',
); );
$ret = $this->bs->bookmarksExist($bms); $ret = $this->bs->bookmarksExist($bms);
$this->assertType('array', $ret); $this->assertInternalType('array', $ret);
$this->assertEquals(3, count($ret)); $this->assertEquals(3, count($ret));
$this->assertFalse($ret['does-not-exist']); $this->assertFalse($ret['does-not-exist']);
$this->assertFalse($ret['does-not-exist-2']); $this->assertFalse($ret['does-not-exist-2']);
@ -367,7 +366,7 @@ class BookmarkTest extends TestBase
'does-not-exist-3' 'does-not-exist-3'
) )
); );
$this->assertType('array', $ret); $this->assertInternalType('array', $ret);
$this->assertEquals(5, count($ret)); $this->assertEquals(5, count($ret));
$this->assertTrue($ret[$bookmark['bAddress']]); $this->assertTrue($ret[$bookmark['bAddress']]);
$this->assertTrue($ret[$bookmark2['bAddress']]); $this->assertTrue($ret[$bookmark2['bAddress']]);
@ -476,7 +475,7 @@ class BookmarkTest extends TestBase
foreach ($bms['bookmarks'] as $bm) { foreach ($bms['bookmarks'] as $bm) {
$this->assertArrayHasKey('tags', $bm); $this->assertArrayHasKey('tags', $bm);
$this->assertType('array', $bm['tags']); $this->assertInternalType('array', $bm['tags']);
if ($bm['bId'] == $bid) { if ($bm['bId'] == $bid) {
$this->assertContains('foo', $bm['tags']); $this->assertContains('foo', $bm['tags']);
$this->assertContains('bar', $bm['tags']); $this->assertContains('bar', $bm['tags']);
@ -757,7 +756,7 @@ class BookmarkTest extends TestBase
$bm = $this->bs->getBookmark($bid, true); $bm = $this->bs->getBookmark($bid, true);
$this->assertArrayHasKey('tags', $bm); $this->assertArrayHasKey('tags', $bm);
$this->assertType('array', $bm['tags']); $this->assertInternalType('array', $bm['tags']);
$this->assertContains('foo', $bm['tags']); $this->assertContains('foo', $bm['tags']);
$this->assertContains('bar', $bm['tags']); $this->assertContains('bar', $bm['tags']);
} }
@ -875,7 +874,7 @@ class BookmarkTest extends TestBase
$bid = $this->addBookmark($uid, $url); $bid = $this->addBookmark($uid, $url);
$bm = $this->bs->getBookmarkByAddress($url); $bm = $this->bs->getBookmarkByAddress($url);
$this->assertType('array', $bm); $this->assertInternalType('array', $bm);
$this->assertEquals($url, $bm['bAddress']); $this->assertEquals($url, $bm['bAddress']);
} }
@ -901,7 +900,7 @@ class BookmarkTest extends TestBase
$bid = $this->addBookmark($uid, $url); $bid = $this->addBookmark($uid, $url);
$bm = $this->bs->getBookmarkByAddress($incomplete); $bm = $this->bs->getBookmarkByAddress($incomplete);
$this->assertType('array', $bm); $this->assertInternalType('array', $bm);
$this->assertEquals($url, $bm['bAddress']); $this->assertEquals($url, $bm['bAddress']);
} }
@ -952,7 +951,7 @@ class BookmarkTest extends TestBase
$this->assertEquals('new description', $bm['bDescription']); $this->assertEquals('new description', $bm['bDescription']);
$this->assertEquals('new private note', $bm['bPrivateNote']); $this->assertEquals('new private note', $bm['bPrivateNote']);
$this->assertEquals(1, $bm['bStatus']); $this->assertEquals(1, $bm['bStatus']);
$this->assertType('array', $bm['tags']); $this->assertInternalType('array', $bm['tags']);
$this->assertEquals(1, count($bm['tags'])); $this->assertEquals(1, count($bm['tags']));
$this->assertContains('new', $bm['tags']); $this->assertContains('new', $bm['tags']);
} }
@ -982,6 +981,38 @@ class BookmarkTest extends TestBase
$this->assertEquals('newShortNambb', $bm['bShort']); $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']);
}
/** /**
@ -1085,6 +1116,92 @@ 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 * Test what countOther() returns when the user is logged in
* and friends (people on the watchlist) have bookmarked * and friends (people on the watchlist) have bookmarked
@ -1092,7 +1209,7 @@ class BookmarkTest extends TestBase
* *
* @return void * @return void
*/ */
public function testCountOthersWatchlist() public function testCountOthersWatchlistComplex()
{ {
$uid = $this->addUser(); $uid = $this->addUser();
$address = 'http://example.org'; $address = 'http://example.org';

View File

@ -12,13 +12,12 @@
* @license GPL http://www.gnu.org/licenses/gpl.html * @license GPL http://www.gnu.org/licenses/gpl.html
* @link http://sourceforge.net/projects/semanticscuttle * @link http://sourceforge.net/projects/semanticscuttle
*/ */
require_once 'prepare.php';
if (!defined('PHPUnit_MAIN_METHOD')) { if (!defined('PHPUnit_MAIN_METHOD')) {
define('PHPUnit_MAIN_METHOD', 'CommonDescriptionTest::main'); define('PHPUnit_MAIN_METHOD', 'CommonDescriptionTest::main');
} }
require_once 'prepare.php';
/** /**
* Unit tests for the SemanticScuttle common description service. * Unit tests for the SemanticScuttle common description service.
* *

View File

@ -12,13 +12,12 @@
* @license GPL http://www.gnu.org/licenses/gpl.html * @license GPL http://www.gnu.org/licenses/gpl.html
* @link http://sourceforge.net/projects/semanticscuttle * @link http://sourceforge.net/projects/semanticscuttle
*/ */
require_once 'prepare.php';
if (!defined('PHPUnit_MAIN_METHOD')) { if (!defined('PHPUnit_MAIN_METHOD')) {
define('PHPUnit_MAIN_METHOD', 'SearchHistoryTest::main'); define('PHPUnit_MAIN_METHOD', 'SearchHistoryTest::main');
} }
require_once 'prepare.php';
/** /**
* Unit tests for the SemanticScuttle search history service. * 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() protected function setUp()
{ {
$this->us =SemanticScuttle_Service_Factory::get('User'); $this->us = SemanticScuttle_Service_Factory::get('User');
$this->bs =SemanticScuttle_Service_Factory::get('Bookmark'); $this->bs = SemanticScuttle_Service_Factory::get('Bookmark');
$this->bs->deleteAll(); $this->bs->deleteAll();
$this->b2ts =SemanticScuttle_Service_Factory::get('Bookmark2Tag'); $this->b2ts =SemanticScuttle_Service_Factory::get('Bookmark2Tag');
$this->b2ts->deleteAll(); $this->b2ts->deleteAll();
$this->tts =SemanticScuttle_Service_Factory::get('Tag2Tag');
$this->tts = SemanticScuttle_Service_Factory::get('Tag2Tag');
$this->tts->deleteAll(); $this->tts->deleteAll();
$this->tsts =SemanticScuttle_Service_Factory::get('TagStat');
$this->tsts = SemanticScuttle_Service_Factory::get('TagStat');
$this->tsts->deleteAll(); $this->tsts->deleteAll();
$this->shs =SemanticScuttle_Service_Factory::get('SearchHistory');
$this->shs = SemanticScuttle_Service_Factory::get('SearchHistory');
$this->shs->deleteAll(); $this->shs->deleteAll();
} }
public function testSearchHistory() /**
* Tests if adding searches to the database works
*
* @covers SemanticScuttle_Service_SearchHistory::addSearch
*/
public function testAddSearch()
{ {
$shs = $this->shs; $this->assertEquals(0, $this->shs->countSearches());
$terms = 'bbqsdkbb;,:,:q;,qddds&é"\'\\\\\(-è_çà)'; $this->assertTrue(
$terms2 = '~#{|`]'; $this->shs->addSearch('testsearchterm', 'all', 0)
$range = 'all'; );
$nbResults = 10908; $this->assertEquals(1, $this->shs->countSearches());
$uId = 10; }
$shs->addSearch($terms, $range, $nbResults, $uId); /**
$shs->addSearch($terms2, $range, $nbResults, $uId); * Tests if adding a search without terms should fail
$shs->addSearch('', $range, $nbResults, $uId); // A void search must not be saved *
* @covers SemanticScuttle_Service_SearchHistory::addSearch
*/
public function testAddSearchNoTerms()
{
$this->assertEquals(0, $this->shs->countSearches());
$searches = $shs->getAllSearches(); $this->assertFalse(
$this->assertSame(2, count($searches)); $this->shs->addSearch('', 'all', 0)
$searches = $shs->getAllSearches($range, $uId); );
$this->assertEquals(2, count($searches)); $this->assertEquals(0, $this->shs->countSearches());
$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(); * Tests if adding a search deletes the history if it is too
$this->assertSame($terms2, $searches[0]['shTerms']); * large.
$this->assertSame($range, $searches[0]['shRange']); *
$this->assertEquals($nbResults, $searches[0]['shNbResults']); * @covers SemanticScuttle_Service_SearchHistory::addSearch
$this->assertEquals($uId, $searches[0]['uId']); */
$this->assertSame($terms, $searches[1]['shTerms']); public function testAddSearchDeleteHistory()
$this->assertSame($range, $searches[1]['shRange']); {
$this->assertEquals($nbResults, $searches[1]['shNbResults']); $this->assertEquals(0, $this->shs->countSearches());
$this->assertEquals($uId, $searches[1]['uId']);
//test distinct parameter $this->shs->sizeSearchHistory = 5;
$shs->addSearch($terms, $range, $nbResults, 30); // we repeat a search (same terms) $this->shs->addSearch('eins', 'all', 1);
$searches = $shs->getAllSearches(); $this->shs->addSearch('zwei', 'all', 1);
$this->assertSame(3, count($searches)); $this->shs->addSearch('drei', 'all', 1);
$searches = $shs->getAllSearches(NULL, NULL, NULL, NULL, true); $this->shs->addSearch('view', 'all', 1);
$this->assertSame(2, count($searches)); $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());
} }
} }

View File

@ -12,13 +12,12 @@
* @license GPL http://www.gnu.org/licenses/gpl.html * @license GPL http://www.gnu.org/licenses/gpl.html
* @link http://sourceforge.net/projects/semanticscuttle * @link http://sourceforge.net/projects/semanticscuttle
*/ */
require_once 'prepare.php';
if (!defined('PHPUnit_MAIN_METHOD')) { if (!defined('PHPUnit_MAIN_METHOD')) {
define('PHPUnit_MAIN_METHOD', 'Tag2TagTest::main'); define('PHPUnit_MAIN_METHOD', 'Tag2TagTest::main');
} }
require_once 'prepare.php';
/** /**
* Unit tests for the SemanticScuttle tag2tag service. * Unit tests for the SemanticScuttle tag2tag service.
* *

View File

@ -12,13 +12,12 @@
* @license GPL http://www.gnu.org/licenses/gpl.html * @license GPL http://www.gnu.org/licenses/gpl.html
* @link http://sourceforge.net/projects/semanticscuttle * @link http://sourceforge.net/projects/semanticscuttle
*/ */
require_once 'prepare.php';
if (!defined('PHPUnit_MAIN_METHOD')) { if (!defined('PHPUnit_MAIN_METHOD')) {
define('PHPUnit_MAIN_METHOD', 'TagTest::main'); define('PHPUnit_MAIN_METHOD', 'TagTest::main');
} }
require_once 'prepare.php';
/** /**
* Unit tests for the SemanticScuttle tag service. * Unit tests for the SemanticScuttle tag service.
* *

View File

@ -12,13 +12,12 @@
* @license GPL http://www.gnu.org/licenses/gpl.html * @license GPL http://www.gnu.org/licenses/gpl.html
* @link http://sourceforge.net/projects/semanticscuttle * @link http://sourceforge.net/projects/semanticscuttle
*/ */
require_once 'prepare.php';
if (!defined('PHPUnit_MAIN_METHOD')) { if (!defined('PHPUnit_MAIN_METHOD')) {
define('PHPUnit_MAIN_METHOD', 'TagsCacheTest::main'); define('PHPUnit_MAIN_METHOD', 'TagsCacheTest::main');
} }
require_once 'prepare.php';
/** /**
* Unit tests for the SemanticScuttle tags cache service. * Unit tests for the SemanticScuttle tags cache service.
* *
@ -54,9 +53,6 @@ class TagsCacheTest extends PHPUnit_Framework_TestCase
protected function setUp() 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->us =SemanticScuttle_Service_Factory::get('User');
$this->bs =SemanticScuttle_Service_Factory::get('Bookmark'); $this->bs =SemanticScuttle_Service_Factory::get('Bookmark');
$this->bs->deleteAll(); $this->bs->deleteAll();

View File

@ -11,10 +11,6 @@
* @link http://sourceforge.net/projects/semanticscuttle * @link http://sourceforge.net/projects/semanticscuttle
*/ */
require_once 'PHPUnit/Framework.php';
PHPUnit_Util_Filter::addFileToFilter(__FILE__);
/** /**
* Base unittest class that provides several helper methods. * 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, * @param array $tags Array of tags to attach. If "null" is given,
* it will automatically be "unittest" * it will automatically be "unittest"
* @param string $title Bookmark title * @param string $title Bookmark title
* @param string $date strtotime-compatible string
* *
* @return integer ID of bookmark * @return integer ID of bookmark
* *
@ -42,7 +39,7 @@ class TestBase extends PHPUnit_Framework_TestCase
*/ */
protected function addBookmark( protected function addBookmark(
$user = null, $address = null, $status = 0, $user = null, $address = null, $status = 0,
$tags = null, $title = null $tags = null, $title = null, $date = null
) { ) {
if ($user === null) { if ($user === null) {
$user = $this->addUser(); $user = $this->addUser();
@ -68,7 +65,7 @@ class TestBase extends PHPUnit_Framework_TestCase
null, null,
$status, $status,
$tags, $tags,
null, null, false, false, null, $date, false, false,
$user $user
); );
return $bid; return $bid;
@ -83,8 +80,25 @@ class TestBase extends PHPUnit_Framework_TestCase
* @param string $password Password * @param string $password Password
* *
* @return integer ID of user * @return integer ID of user
*
* @uses addUserData()
*/ */
protected function addUser($username = null, $password = null) 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'); $us = SemanticScuttle_Service_Factory::get('User');
$rand = rand(); $rand = rand();
@ -101,9 +115,37 @@ class TestBase extends PHPUnit_Framework_TestCase
$password, $password,
'unittest-' . $rand . '@example.org' '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;
}
} }
?> ?>

View File

@ -11,10 +11,6 @@
* @link http://sourceforge.net/projects/semanticscuttle * @link http://sourceforge.net/projects/semanticscuttle
*/ */
require_once 'PHPUnit/Framework.php';
PHPUnit_Util_Filter::addFileToFilter(__FILE__);
/** /**
* Base unittest class for web API tests. * Base unittest class for web API tests.
* *
@ -29,6 +25,16 @@ class TestBaseApi extends TestBase
protected $url; protected $url;
protected $urlPart = null; protected $urlPart = null;
/**
* @var SemanticScuttle_Service_User
*/
protected $us;
/**
* @var SemanticScuttle_Service_Bookmark
*/
protected $bs;
protected function setUp() 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 * @param string $urlSuffix Suffix for the URL
* *
* @return HTTP_Request2 HTTP request object * @return HTTP_Request2 HTTP request object
*
* @uses $url
*/ */
protected function getRequest($urlSuffix = null) 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 string $urlSuffix Suffix for the URL
* @param mixed $auth If user authentication is needed (true/false) * @param mixed $auth If user authentication is needed (true/false)
* or array with username and password * or array with username and password
* *
* @return array(HTTP_Request2, integer) HTTP request object and user id * @return array(HTTP_Request2, integer) HTTP request object and user id
*
* @uses getRequest()
*/ */
protected function getAuthRequest($urlSuffix = null, $auth = true) protected function getAuthRequest($urlSuffix = null, $auth = true)
{ {
@ -96,5 +124,102 @@ class TestBaseApi extends TestBase
return array($req, $uid); 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'
);
}
} }
?> ?>

68
tests/UserArrayTest.php Normal file
View File

@ -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'
)
)
);
}
}
?>

View File

@ -12,13 +12,12 @@
* @license GPL http://www.gnu.org/licenses/gpl.html * @license GPL http://www.gnu.org/licenses/gpl.html
* @link http://sourceforge.net/projects/semanticscuttle * @link http://sourceforge.net/projects/semanticscuttle
*/ */
require_once 'prepare.php';
if (!defined('PHPUnit_MAIN_METHOD')) { if (!defined('PHPUnit_MAIN_METHOD')) {
define('PHPUnit_MAIN_METHOD', 'UserTest::main'); define('PHPUnit_MAIN_METHOD', 'UserTest::main');
} }
require_once 'prepare.php';
/** /**
* Unit tests for the SemanticScuttle user service. * Unit tests for the SemanticScuttle user service.
* *
@ -211,7 +210,7 @@ class UserTest extends TestBase
$uid = $this->addUser(); $uid = $this->addUser();
$users = $this->us->getObjectUsers(); $users = $this->us->getObjectUsers();
$this->assertEquals(1, count($users)); $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(); $uid3 = $this->addUser();
$users = $this->us->getObjectUsers(); $users = $this->us->getObjectUsers();
$this->assertEquals(3, count($users)); $this->assertEquals(3, count($users));
$this->assertType('SemanticScuttle_Model_User', reset($users)); $this->assertInstanceOf('SemanticScuttle_Model_User', reset($users));
} }

View File

@ -10,13 +10,12 @@
* @license GPL http://www.gnu.org/licenses/gpl.html * @license GPL http://www.gnu.org/licenses/gpl.html
* @link http://sourceforge.net/projects/semanticscuttle * @link http://sourceforge.net/projects/semanticscuttle
*/ */
require_once 'prepare.php';
if (!defined('PHPUnit_MAIN_METHOD')) { if (!defined('PHPUnit_MAIN_METHOD')) {
define('PHPUnit_MAIN_METHOD', 'VoteTest::main'); define('PHPUnit_MAIN_METHOD', 'VoteTest::main');
} }
require_once 'prepare.php';
/** /**
* Unit tests for the SemanticScuttle voting system. * Unit tests for the SemanticScuttle voting system.
* *

View File

@ -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();
}
?>

View File

@ -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);
}
}
?>

View File

@ -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));
}
}
?>

8
tests/phpunit.xml Normal file
View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8" ?>
<phpunit>
<filter>
<blacklist>
<directory suffix=".php">.</directory>
</blacklist>
</filter>
</phpunit>

View File

@ -19,7 +19,13 @@
$_SERVER['HTTP_HOST'] = 'http://localhost/'; $_SERVER['HTTP_HOST'] = 'http://localhost/';
define('UNIT_TEST_MODE', true); 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__) . '/TestBase.php';
require_once dirname(__FILE__) . '/TestBaseApi.php'; require_once dirname(__FILE__) . '/TestBaseApi.php';

View File

@ -1,64 +1,92 @@
<?php <?php
/*************************************************************************** /**
Copyright (C) 2004 - 2006 Scuttle project * Returns a list of tags managed by the admins, in json format
http://sourceforge.net/projects/scuttle/ * suitable for jsTree consumption.
http://scuttle.org/ *
* @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'; $httpContentType = 'application/json';
require_once '../www-header.php'; require_once '../www-header.php';
/* Service creation: only useful services are created */ /**
$b2tservice =SemanticScuttle_Service_Factory::get('Bookmark2Tag'); * Creates and returns an array of tags for the jsTree ajax loader.
$bookmarkservice =SemanticScuttle_Service_Factory::get('Tag'); * If the tag is empty, the configured menu2 (admin) main tags are used.
$tagstatservice =SemanticScuttle_Service_Factory::get('TagStat'); *
* @param string $tag Tag name to fetch subtags for
/* Managing all possible inputs */ * @param SemanticScuttle_Service_Tag2Tag $t2t Tag relation service
isset($_GET['tag']) ? define('GET_TAG', $_GET['tag']): define('GET_TAG', ''); *
isset($_GET['uId']) ? define('GET_UID', $_GET['uId']): define('GET_UID', ''); * @return array Array of tag data suitable for the jsTree ajax loader
*/
function assembleAdminTagData($tag, SemanticScuttle_Service_Tag2Tag $t2t)
function displayTag($tag, $uId) { {
$uId = ($uId==0)?NULL:$uId; // if user is nobody, NULL allows to look for every public tags if ($tag == '') {
$linkedTags = $GLOBALS['menu2Tags'];
$tag2tagservice =SemanticScuttle_Service_Factory::get('Tag2Tag'); } else {
$output = '{ id:'.rand().', name:\''.$tag.'\''; $linkedTags = $t2t->getAdminLinkedTags($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.= "]";
} }
$output.= '},'; $tagData = array();
return $output; 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;
} }
?> /**
* 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';
}
{ label: 'name', identifier: 'id', items: [ return $ar;
<?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);
?> ?>
] }

View File

@ -1,44 +1,47 @@
<?php <?php
/*************************************************************************** /**
Copyright (C) 2004 - 2006 Scuttle project * Return a json file with list of public tags used by admins and sorted
http://sourceforge.net/projects/scuttle/ * by popularity.
http://scuttle.org/ *
* 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'; $httpContentType = 'application/json';
require_once '../www-header.php'; require_once '../www-header.php';
/* Service creation: only useful services are created */ $limit = 30;
$b2tservice =SemanticScuttle_Service_Factory::get('Bookmark2Tag'); $beginsWith = null;
$bookmarkservice =SemanticScuttle_Service_Factory::get('Tag'); $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);
?> ?>
{identifier:"tag",
items: [
<?php
$listTags = $b2tservice->getAdminTags(1000, $userservice->getCurrentUserId());
foreach($listTags as $t) {
echo "{tag: \"".$t['tag']."\"},";
}
?>
]}

View File

@ -1,44 +1,47 @@
<?php <?php
/*************************************************************************** /**
Copyright (C) 2004 - 2006 Scuttle project * Return a json file with list of tags according to current user
http://sourceforge.net/projects/scuttle/ * and sorted by popularity.
http://scuttle.org/ *
* 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'; $httpContentType = 'application/json';
require_once '../www-header.php'; require_once '../www-header.php';
/* Service creation: only useful services are created */ $limit = 30;
$b2tservice =SemanticScuttle_Service_Factory::get('Bookmark2Tag'); $beginsWith = null;
$bookmarkservice =SemanticScuttle_Service_Factory::get('Tag'); $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']."\"},";
}
?>
]}

View File

@ -1,64 +1,142 @@
<?php <?php
/*************************************************************************** /**
Copyright (C) 2004 - 2006 Scuttle project * Returns a list of tags linked to the given one,
http://sourceforge.net/projects/scuttle/ * suitable for jsTree consumption.
http://scuttle.org/ *
* Accepted GET parameters:
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 * @param string $tag Tag for which the children tags shall be returned
the Free Software Foundation; either version 2 of the License, or * Multiple tags (separated with space or "+") are
(at your option) any later version. * supported.
* If no tag is given, all top-level tags are loaded.
This program is distributed in the hope that it will be useful, * @param integer $uId User ID to fetch the tags for
but WITHOUT ANY WARRANTY; without even the implied warranty of * @param boolean $parent Load parent tags
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
GNU General Public License for more details. * SemanticScuttle - your social bookmark manager.
*
You should have received a copy of the GNU General Public License * PHP version 5.
along with this program; if not, write to the Free Software *
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * @category Bookmarking
***************************************************************************/ * @package SemanticScuttle
* @subpackage Templates
/* Return a json file with list of linked tags */ * @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'; $httpContentType = 'application/json';
require_once '../www-header.php'; require_once '../www-header.php';
/* Service creation: only useful services are created */ $tag = isset($_GET['tag']) ? $_GET['tag'] : null;
$b2tservice =SemanticScuttle_Service_Factory::get('Bookmark2Tag'); $uId = isset($_GET['uId']) ? (int)$_GET['uId'] : 0;
$bookmarkservice =SemanticScuttle_Service_Factory::get('Tag'); $loadParentTags = isset($_GET['parent']) ? (bool)$_GET['parent'] : false;
$tagstatservice =SemanticScuttle_Service_Factory::get('TagStat');
/* Managing all possible inputs */ $tags = explode(' ', trim($tag));
isset($_GET['tag']) ? define('GET_TAG', $_GET['tag']): define('GET_TAG', ''); if (count($tags) == 1 && $tags[0] == '') {
isset($_GET['uId']) ? define('GET_UID', $_GET['uId']): define('GET_UID', ''); //no tags
$tags = array();
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->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.= "]";
}
$output.= '},';
return $output;
} }
?>
{ label: 'name', identifier: 'id', items: [ function assembleLinkedTagData(
<?php $tags, $uId, $loadParentTags, SemanticScuttle_Service_Tag2Tag $t2t
$json = displayTag(GET_TAG, intval(GET_UID)); ) {
$json = substr($json, 0, -1); // remove final comma avoiding IE6 Dojo bug $tagData = array();
echo $json;
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;
}
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;
}
/**
* 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;
}
$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';
}
return $ar;
}
$tagData = assembleLinkedTagData(
$tags, 0/*$uId*/, $loadParentTags,
SemanticScuttle_Service_Factory::get('Tag2Tag')
);
echo json_encode($tagData);
?> ?>
] }

View File

@ -22,6 +22,8 @@
// del.icio.us behavior: // del.icio.us behavior:
// - doesn't include the filtered tag as an attribute on the root element (we do) // - 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! // Force HTTP authentication first!
require_once 'httpauth.inc.php'; require_once 'httpauth.inc.php';

View File

@ -1,10 +1,29 @@
<?php <?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'; require_once '../www-header.php';
// Provides HTTP Basic authentication of a user /**
// and logs the user in if necessary * Sends HTTP auth headers to the browser
*/
function authenticate() { function authenticate()
{
header('WWW-Authenticate: Basic realm="SemanticScuttle API"'); header('WWW-Authenticate: Basic realm="SemanticScuttle API"');
header('HTTP/1.0 401 Unauthorized'); header('HTTP/1.0 401 Unauthorized');
@ -26,7 +45,9 @@ if (!$userservice->isLoggedOn()) {
if (!isset($_SERVER['PHP_AUTH_USER'])) { if (!isset($_SERVER['PHP_AUTH_USER'])) {
authenticate(); authenticate();
} else { } 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) { if ($login) {
$currentUser = $userservice->getCurrentObjectUser(); $currentUser = $userservice->getCurrentObjectUser();
} else { } else {

View File

@ -1,54 +1,92 @@
<?php <?php
// Implements the del.icio.us API request to add a new post. /**
// http://delicious.com/help/api#posts_add * API for adding a new bookmark.
*
// del.icio.us behavior: * The following POST and GET parameters are accepted:
// - tags can't have spaces * @param string $url URL of the bookmark (required)
// - address and description are mandatory * @param string $description Bookmark title (required)
* @param string $extended Extended bookmark description (optional)
// Scuttle behavior: * @param string $tags Space-separated list of tags (optional)
// - Additional 'status' variable for privacy * @param string $dt Date and time of bookmark creation (optional)
// - No support for 'replace' variable * 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 // Force HTTP authentication
$httpContentType = 'text/xml'; $httpContentType = 'text/xml';
require_once 'httpauth.inc.php'; require_once 'httpauth.inc.php';
/* Service creation: only useful services are created */ $bs = SemanticScuttle_Service_Factory::get('Bookmark');
$bookmarkservice =SemanticScuttle_Service_Factory::get('Bookmark');
// Get all the bookmark's passed-in information // 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'])); $url = trim(urldecode($_REQUEST['url']));
else } else {
$url = NULL; $url = null;
}
if (isset($_REQUEST['description']) && (trim($_REQUEST['description']) != '')) if (isset($_REQUEST['description']) && (trim($_REQUEST['description']) != '')) {
$description = trim($_REQUEST['description']); $description = trim($_REQUEST['description']);
else } else {
$description = NULL; $description = null;
}
if (isset($_REQUEST['extended']) && (trim($_REQUEST['extended']) != "")) if (isset($_REQUEST['extended']) && (trim($_REQUEST['extended']) != '')) {
$extended = trim($_REQUEST['extended']); $extended = trim($_REQUEST['extended']);
else } else {
$extended = NULL; $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']); $tags = trim($_REQUEST['tags']);
else } else {
$tags = NULL; $tags = null;
}
if (isset($_REQUEST['dt']) && (trim($_REQUEST['dt']) != '')) if (isset($_REQUEST['dt']) && (trim($_REQUEST['dt']) != '')) {
$dt = trim($_REQUEST['dt']); $dt = trim($_REQUEST['dt']);
else } else {
$dt = NULL; $dt = null;
}
$replace = isset($_REQUEST['replace']) && ($_REQUEST['replace'] == 'yes');
$status = 0; $status = 0;
if (isset($_REQUEST['status'])) { if (isset($_REQUEST['status'])) {
$status_str = trim($_REQUEST['status']); $status_str = trim($_REQUEST['status']);
if (is_numeric($status_str)) { if (is_numeric($status_str)) {
$status = intval($status_str); $status = intval($status_str);
if($status < 0 || $status > 2) { if ($status < 0 || $status > 2) {
$status = 0; $status = 0;
} }
} else { } else {
@ -71,17 +109,38 @@ if (isset($_REQUEST['shared']) && (trim($_REQUEST['shared']) == 'no')) {
} }
// Error out if there's no address or description // Error out if there's no address or description
if (is_null($url) || is_null($description)) { if (is_null($url)) {
$added = false; 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 { } else {
// We're good with info; now insert it! // We're good with info; now insert it!
if ($bookmarkservice->bookmarkExists($url, $userservice->getCurrentUserId())) $exists = $bs->bookmarkExists($url, $userservice->getCurrentUserId());
$added = false; if ($exists) {
else if (!$replace) {
$added = $bookmarkservice->addBookmark($url, $description, $extended, '', $status, $tags, null, $dt, true); 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. // Set up the XML file and output the result.
echo '<?xml version="1.0" standalone="yes" ?'.">\r\n"; echo '<?xml version="1.0" standalone="yes" ?' . ">\r\n";
echo '<result code="'. ($added ? 'done' : 'something went wrong') .'" />'; echo '<result code="' . $msg .'" />';
?> ?>

View File

@ -1,33 +1,57 @@
<?php <?php
// Implements the del.icio.us API request to delete a post. /**
* API for deleting a bookmark.
// del.icio.us behavior: * The delicious API is implemented here.
// - returns "done" even if the bookmark doesn't exist; *
// - does NOT allow the hash for the url parameter; * The delicious API behaves like that:
// - doesn't set the Content-Type to text/xml (we do). * - 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! // Force HTTP authentication first!
$httpContentType = 'text/xml'; $httpContentType = 'text/xml';
require_once 'httpauth.inc.php'; require_once 'httpauth.inc.php';
/* Service creation: only useful services are created */ $bs = SemanticScuttle_Service_Factory::get('Bookmark');
$bookmarkservice =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 // Error out if there's no address
if (is_null($_REQUEST['url'])) { if (!isset($_REQUEST['url'])
$deleted = false; || $_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 { } else {
$bookmark = $bookmarkservice->getBookmarkByAddress($_REQUEST['url']); $bookmark = $bs->getBookmarkByAddress($_REQUEST['url'], false);
$bid = $bookmark['bId']; $bId = $bookmark['bId'];
$delete = $bookmarkservice->deleteBookmark($bid); $deleted = $bs->deleteBookmark($bId);
$deleted = true; $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. // Set up the XML file and output the result.
echo '<?xml version="1.0" standalone="yes" ?'.">\r\n"; echo '<?xml version="1.0" standalone="yes" ?' . ">\r\n";
echo '<result code="'. ($deleted ? 'done' : 'something went wrong') .'" />'; echo '<result code="' . $msg . '" />';
?> ?>

View File

@ -1,24 +1,44 @@
<?php <?php
// Implements the del.icio.us API request for a user's last update time and date. /**
* API for retrieving a user's last update time.
// del.icio.us behavior: * That is the time the user changed a bookmark lastly.
// - doesn't set the Content-Type to text/xml (we do). * 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! // Force HTTP authentication first!
$httpContentType = 'text/xml'; $httpContentType = 'text/xml';
require_once 'httpauth.inc.php'; require_once 'httpauth.inc.php';
/* Service creation: only useful services are created */ $bs = SemanticScuttle_Service_Factory::get('Bookmark');
$bookmarkservice =SemanticScuttle_Service_Factory::get('Bookmark');
// Get the posts relevant to the passed-in variables.
$bookmarks =& $bookmarkservice->getBookmarks(0, 1, $userservice->getCurrentUserId());
$bookmarks = $bs->getBookmarks(0, 1, $userservice->getCurrentUserId());
// Set up the XML file and output all the tags. // Set up the XML file and output all the tags.
echo '<?xml version="1.0" standalone="yes" ?'.">\r\n"; echo '<?xml version="1.0" standalone="yes" ?' . ">\r\n";
foreach($bookmarks['bookmarks'] as $row) { //foreach is used in case there are no bookmarks
echo '<update time="'. gmdate('Y-m-d\TH:i:s\Z', strtotime($row['bDatetime'])) .'" />'; foreach ($bookmarks['bookmarks'] as $row) {
echo '<update time="'
. gmdate('Y-m-d\TH:i:s\Z', strtotime($row['bDatetime']))
. '"'
. ' inboxnew="0"'
. ' />';
} }
?> ?>

View File

@ -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['description']) ? define('POST_DESCRIPTION', $_POST['description']): define('POST_DESCRIPTION', '');
isset($_POST['privateNote']) ? define('POST_PRIVATENOTE', $_POST['privateNote']): define('POST_PRIVATENOTE', ''); isset($_POST['privateNote']) ? define('POST_PRIVATENOTE', $_POST['privateNote']): define('POST_PRIVATENOTE', '');
isset($_POST['status']) ? define('POST_STATUS', $_POST['status']): define('POST_STATUS', ''); 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($_POST['referrer']) ? define('POST_REFERRER', $_POST['referrer']): define('POST_REFERRER', '');
isset($_GET['popup']) ? define('GET_POPUP', $_GET['popup']): define('GET_POPUP', ''); 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['page']) ? define('GET_PAGE', $_GET['page']): define('GET_PAGE', 0);
isset($_GET['sort']) ? define('GET_SORT', $_GET['sort']): define('GET_SORT', ''); 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()) { if ((GET_ACTION == "add") && !$userservice->isLoggedOn()) {
@ -143,7 +146,7 @@ if ($userservice->isLoggedOn() && POST_SUBMITTED != '') {
$description = trim(POST_DESCRIPTION); $description = trim(POST_DESCRIPTION);
$privateNote = trim(POST_PRIVATENOTE); $privateNote = trim(POST_PRIVATENOTE);
$status = intval(POST_STATUS); $status = intval(POST_STATUS);
$categories = trim(POST_TAGS); $categories = explode(',', $_POST['tags']);
$saved = true; $saved = true;
if ($bookmarkservice->addBookmark($address, $title, $description, $privateNote, $status, $categories)) { if ($bookmarkservice->addBookmark($address, $title, $description, $privateNote, $status, $categories)) {
if (POST_POPUP != '') { if (POST_POPUP != '') {
@ -184,10 +187,10 @@ if ($templatename == 'editbookmark.tpl') {
'bAddress' => stripslashes(POST_ADDRESS), 'bAddress' => stripslashes(POST_ADDRESS),
'bDescription' => stripslashes(POST_DESCRIPTION), 'bDescription' => stripslashes(POST_DESCRIPTION),
'bPrivateNote' => stripslashes(POST_PRIVATENOTE), 'bPrivateNote' => stripslashes(POST_PRIVATENOTE),
'tags' => (POST_TAGS ? explode(',', stripslashes(POST_TAGS)) : array()), 'tags' => ($_POST['tags'] ? $_POST['tags'] : array()),
'bStatus' => 0, 'bStatus' => 0,
); );
$tplVars['tags'] = POST_TAGS; $tplVars['tags'] = $_POST['tags'];
} else { } else {
if(GET_COPYOF != '') { //copy from bookmarks page if(GET_COPYOF != '') { //copy from bookmarks page
$tplVars['row'] = $bookmarkservice->getBookmark(intval(GET_COPYOF), true); $tplVars['row'] = $bookmarkservice->getBookmark(intval(GET_COPYOF), true);

View File

@ -31,7 +31,9 @@ if($GLOBALS['enableGoogleCustomSearch']==false) {
echo '<p><small>'; echo '<p><small>';
echo T_('Admin tips: '); echo T_('Admin tips: ');
echo T_('To refresh manually Google Custom Search Engine, goes to: '); 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 T_('If no result appears, check that all the urls are valid in the admin section.');
echo '</small></p>'; echo '</small></p>';

View File

@ -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));

View File

@ -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);

View File

@ -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 );

View File

@ -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);

View File

@ -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 ));

View File

@ -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);

View File

@ -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 );

Some files were not shown because too many files have changed in this diff Show More