33 files changed, 2321 insertions, 0 deletions
@@ -0,0 +1,3 @@ | |||
1 | Klever dissected: | ||
2 | Michael 'hacker' Krelin <hacker@klever.net> | ||
3 | Leonid Ivanov <kamel@klever.net> | ||
@@ -0,0 +1,19 @@ | |||
1 | Copyright (c) 2006 Klever Group (http://www.klever.net/) | ||
2 | |||
3 | Permission is hereby granted, free of charge, to any person obtaining a copy of | ||
4 | this software and associated documentation files (the "Software"), to deal in | ||
5 | the Software without restriction, including without limitation the rights to | ||
6 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies | ||
7 | of the Software, and to permit persons to whom the Software is furnished to do | ||
8 | so, subject to the following conditions: | ||
9 | |||
10 | The above copyright notice and this permission notice shall be included in all | ||
11 | copies or substantial portions of the Software. | ||
12 | |||
13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
19 | SOFTWARE. | ||
diff --git a/ChangeLog b/ChangeLog new file mode 100644 index 0000000..e69de29 --- a/dev/null +++ b/ChangeLog | |||
diff --git a/Makefile.am b/Makefile.am new file mode 100644 index 0000000..913b46a --- a/dev/null +++ b/Makefile.am | |||
@@ -0,0 +1,37 @@ | |||
1 | SUBDIRS = content locale | ||
2 | |||
3 | xpi_DATA = \ | ||
4 | install.rdf \ | ||
5 | AUTHORS COPYING NEWS | ||
6 | |||
7 | EXTRA_DIST = NEWS NEWS.xml NEWS.xsl chrome.manifest | ||
8 | |||
9 | XPI=${PACKAGE}-${VERSION}.xpi | ||
10 | |||
11 | xpi: ${XPI} | ||
12 | |||
13 | ${XPI}: install | ||
14 | cd ${xpichromedir} \ | ||
15 | && ${ZIP} -r -m ${PACKAGE}.jar */ | ||
16 | cd ${xpidir} \ | ||
17 | && ${ZIP} -r @abs_builddir@/$@ . | ||
18 | |||
19 | install-data-local: ${xpidir}/chrome.manifest | ||
20 | |||
21 | ${xpidir}/chrome.manifest: chrome.manifest Makefile | ||
22 | sed \ | ||
23 | -e 's,^content[[:space:]]\+\([^[:space:]]\+\)[[:space:]]\+\([^[:space:]]\+\)$$,content \1 jar:chrome/${PACKAGE}.jar!/\2,' \ | ||
24 | -e 's,^locale[[:space:]]\+\([^[:space:]]\+\)[[:space:]]\+\([^[:space:]]\+\)[[:space:]]\+\([^[:space:]]\+\)$$,locale \1 \2 jar:chrome/${PACKAGE}.jar!/\3,' \ | ||
25 | $< >$@ | ||
26 | |||
27 | clean-local: | ||
28 | rm -rf ${xpidir} ${XPI} | ||
29 | |||
30 | all-local: NEWS | ||
31 | |||
32 | NEWS: NEWS.xsl NEWS.xml | ||
33 | ${XSLTPROC} -o $@ NEWS.xsl NEWS.xml | ||
34 | |||
35 | mozextptr: ${MOZ_EXT_ID} | ||
36 | ${MOZ_EXT_ID}: | ||
37 | echo @abs_srcdir@ >$@ | ||
@@ -0,0 +1,2 @@ | |||
1 | 0.0 (September 26th, 2006) | ||
2 | - Initial release | ||
diff --git a/NEWS.xml b/NEWS.xml new file mode 100644 index 0000000..ed82c8a --- a/dev/null +++ b/NEWS.xml | |||
@@ -0,0 +1,6 @@ | |||
1 | <?xml version="1.0" encoding="us-ascii"?> | ||
2 | <news> | ||
3 | <version version="0.0" date="September 26th, 2006"> | ||
4 | <ni>Initial release</ni> | ||
5 | </version> | ||
6 | </news> | ||
diff --git a/NEWS.xsl b/NEWS.xsl new file mode 100644 index 0000000..7c71307 --- a/dev/null +++ b/NEWS.xsl | |||
@@ -0,0 +1,24 @@ | |||
1 | <?xml version="1.0" encoding="us-ascii"?> | ||
2 | <xsl:stylesheet version="1.0" | ||
3 | xmlns:xsl="http://www.w3.org/1999/XSL/Transform" | ||
4 | > | ||
5 | <xsl:output | ||
6 | method="text" | ||
7 | encoding="us-ascii" | ||
8 | media-type="text/plain" /> | ||
9 | |||
10 | <xsl:template match="news"> | ||
11 | <xsl:apply-templates/> | ||
12 | </xsl:template> | ||
13 | <xsl:template match="version"> | ||
14 | <xsl:value-of select="concat(@version,' (',@date,')
')"/> | ||
15 | <xsl:apply-templates/> | ||
16 | </xsl:template> | ||
17 | <xsl:template match="ni"> | ||
18 | <xsl:text> - </xsl:text> | ||
19 | <xsl:apply-templates mode="text"/> | ||
20 | <xsl:text>
</xsl:text> | ||
21 | </xsl:template> | ||
22 | <xsl:template match="*|text()"/> | ||
23 | |||
24 | </xsl:stylesheet> | ||
diff --git a/autogen.sh b/autogen.sh new file mode 100755 index 0000000..1a4b02a --- a/dev/null +++ b/autogen.sh | |||
@@ -0,0 +1,7 @@ | |||
1 | #!/bin/sh | ||
2 | WANT_AUTOMAKE=1.8 | ||
3 | export WANT_AUTOMAKE | ||
4 | aclocal \ | ||
5 | && automake -a \ | ||
6 | && autoconf \ | ||
7 | && ./configure "$@" | ||
diff --git a/chrome.manifest b/chrome.manifest new file mode 100644 index 0000000..3792a2f --- a/dev/null +++ b/chrome.manifest | |||
@@ -0,0 +1,5 @@ | |||
1 | content fireflix content/ | ||
2 | |||
3 | overlay chrome://browser/content/browser.xul chrome://fireflix/content/browser.xul | ||
4 | |||
5 | locale fireflix en-US locale/en-US/ | ||
diff --git a/configure.ac b/configure.ac new file mode 100644 index 0000000..b76ae0f --- a/dev/null +++ b/configure.ac | |||
@@ -0,0 +1,28 @@ | |||
1 | AC_INIT([fireflix], [0.0], [fireflix-bugs@klever.net]) | ||
2 | AC_CONFIG_SRCDIR([install.rdf.in]) | ||
3 | AM_INIT_AUTOMAKE([dist-bzip2]) | ||
4 | AC_SUBST([MOZ_EXT_ID],[{4269f719-86de-4668-b8ad-04752c23a69e}]) | ||
5 | |||
6 | AC_PATH_PROG([ZIP],[zip],[false]) | ||
7 | if test "${ZIP}" = "false" ; then | ||
8 | AC_MSG_ERROR([zip is required to produce packaged extension]) | ||
9 | fi | ||
10 | AC_PATH_PROG([XSLTPROC],[xsltproc],[true]) | ||
11 | |||
12 | AC_SUBST([xpidir],[\${top_builddir}/xpi]) | ||
13 | AC_SUBST([xpichromedir],[\${xpidir}/chrome]) | ||
14 | AC_SUBST([xpichromecontentdir],[\${xpichromedir}/content]) | ||
15 | AC_SUBST([xpichromelocaledir],[\${xpichromedir}/locale]) | ||
16 | |||
17 | COPYING="`sed -e 's/\\"/\\"/g' -e 's,$,<br/>,g' COPYING|tr '\n' ' '`" | ||
18 | AC_SUBST([COPYING]) | ||
19 | |||
20 | AC_CONFIG_FILES([ | ||
21 | Makefile | ||
22 | install.rdf | ||
23 | update.rdf | ||
24 | content/Makefile | ||
25 | content/autoconf.dtd | ||
26 | locale/Makefile | ||
27 | ]) | ||
28 | AC_OUTPUT | ||
diff --git a/content/Makefile.am b/content/Makefile.am new file mode 100644 index 0000000..8548400 --- a/dev/null +++ b/content/Makefile.am | |||
@@ -0,0 +1,22 @@ | |||
1 | xpichromecontent_DATA = \ | ||
2 | autoconf.dtd \ | ||
3 | browser.xul about.xul fireflix-panel.xul photoset-props.xul \ | ||
4 | generated-content.xul \ | ||
5 | photoset-props.js fireflix.js flickr.js md5.js \ | ||
6 | generated-content.js \ | ||
7 | fireflix.css \ | ||
8 | background.jpeg | ||
9 | |||
10 | sized_icons = \ | ||
11 | $(addsuffix .png, \ | ||
12 | fireflix \ | ||
13 | ) | ||
14 | |||
15 | nobase_xpichromecontent_DATA = \ | ||
16 | $(addprefix icons/, \ | ||
17 | $(addprefix 16x16/,${sized_icons}) \ | ||
18 | $(addprefix 32x32/,${sized_icons}) \ | ||
19 | ) | ||
20 | |||
21 | EXTRA_DIST = \ | ||
22 | ${xpichromecontent_DATA} ${nobase_xpichromecontent_DATA} | ||
diff --git a/content/about.xul b/content/about.xul new file mode 100644 index 0000000..1cb13d4 --- a/dev/null +++ b/content/about.xul | |||
@@ -0,0 +1,45 @@ | |||
1 | <?xml version="1.0"?> | ||
2 | <?xml-stylesheet href="chrome://global/skin/" type="text/css"?> | ||
3 | <?xml-stylesheet href="fireflix.css" type="text/css"?> | ||
4 | <!DOCTYPE window SYSTEM "chrome://fireflix/locale/fireflix.dtd"> | ||
5 | <window | ||
6 | xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" | ||
7 | id="aboutFireflix" title="&aboutFireflix;" | ||
8 | orient="vertical" | ||
9 | width="400" height="200" | ||
10 | > | ||
11 | |||
12 | <hbox class="about wholething" flex="1"> | ||
13 | <hbox flex="1" class="insides"> | ||
14 | <vbox> | ||
15 | <spacer flex="1"/> | ||
16 | <image src="icons/32x32/fireflix.png" width="32" height="32" /> | ||
17 | <spacer flex="1"/> | ||
18 | </vbox> | ||
19 | <groupbox flex="1" class="text" orient="vertical"> | ||
20 | <spacer flex="2"/> | ||
21 | <hbox> | ||
22 | <spacer flex="1"/> | ||
23 | <label value="Fireflix &autoconf.version;" class="title"/> | ||
24 | <spacer flex="1"/> | ||
25 | </hbox> | ||
26 | <spacer flex="1"/> | ||
27 | <hbox> | ||
28 | <label value="Copyright © 2006 "/> | ||
29 | <label value="Klever Group" class="link" | ||
30 | onclick="window.openDialog('chrome://browser/content/browser.xul','_blank','chrome,all,dialog=no','http://www.klever.net/',null,null)" /> | ||
31 | </hbox> | ||
32 | <spacer flex="2"/> | ||
33 | </groupbox> | ||
34 | <vbox> | ||
35 | <spacer flex="10" /> | ||
36 | <button label="&about.license.label;" tooltiptext="&about.license.tip;" | ||
37 | oncommand="window.openDialog('chrome://fireflix/content/copying.xul','copying')" /> | ||
38 | <spacer flex="2" /> | ||
39 | <button label="OK" oncommand="window.close()"/> | ||
40 | <spacer flex="1" /> | ||
41 | </vbox> | ||
42 | </hbox> | ||
43 | </hbox> | ||
44 | |||
45 | </window> | ||
diff --git a/content/autoconf.dtd.in b/content/autoconf.dtd.in new file mode 100644 index 0000000..e4ad217 --- a/dev/null +++ b/content/autoconf.dtd.in | |||
@@ -0,0 +1,3 @@ | |||
1 | <!ENTITY autoconf.version "@VERSION@"> | ||
2 | <!ENTITY autoconf.package "@PACKAGE@"> | ||
3 | <!ENTITY autoconf.copying "@COPYING@"> | ||
diff --git a/content/background.jpeg b/content/background.jpeg new file mode 100644 index 0000000..43684f7 --- a/dev/null +++ b/content/background.jpeg | |||
Binary files differ | |||
diff --git a/content/browser.xul b/content/browser.xul new file mode 100644 index 0000000..aaff443 --- a/dev/null +++ b/content/browser.xul | |||
@@ -0,0 +1,19 @@ | |||
1 | <?xml version="1.0"?> | ||
2 | <!DOCTYPE overlay SYSTEM "chrome://fireflix/locale/fireflix.dtd"> | ||
3 | <overlay id="fireflixOverlay" | ||
4 | xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" > | ||
5 | |||
6 | <menupopup id="viewSidebarMenu"> | ||
7 | <menuitem observes="viewFireflixSidebar" /> | ||
8 | </menupopup> | ||
9 | |||
10 | <broadcasterset id="mainBroadcasterSet"> | ||
11 | <broadcaster id="viewFireflixSidebar" | ||
12 | autoCheck="false" label="&browser.sidebar.label;" | ||
13 | type="checkbox" group="sidebar" | ||
14 | sidebarurl="chrome://fireflix/content/fireflix-panel.xul" | ||
15 | sidebartitle="&browser.sidebar.title;" | ||
16 | oncommand="toggleSidebar('viewFireflixSidebar')" /> | ||
17 | </broadcasterset> | ||
18 | </overlay> | ||
19 | |||
diff --git a/content/copying.xul b/content/copying.xul new file mode 100644 index 0000000..179dca5 --- a/dev/null +++ b/content/copying.xul | |||
@@ -0,0 +1,14 @@ | |||
1 | <?xml version="1.0"?> | ||
2 | <?xml-stylesheet href="chrome://global/skin/" type="text/css"?> | ||
3 | <?xml-stylesheet href="fireflix.css" type="text/css"?> | ||
4 | <!DOCTYPE dialog SYSTEM "chrome://fireflix/locale/fireflix.dtd"> | ||
5 | <dialog | ||
6 | xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" | ||
7 | id="copying" title="©ing.title;" orient="vertical" | ||
8 | buttons="accept"> | ||
9 | |||
10 | <div xmlns="http://www.w3.org/1999/xhtml"> | ||
11 | &autoconf.copying; | ||
12 | </div> | ||
13 | |||
14 | </dialog> | ||
diff --git a/content/fireflix-panel.xul b/content/fireflix-panel.xul new file mode 100644 index 0000000..9953761 --- a/dev/null +++ b/content/fireflix-panel.xul | |||
@@ -0,0 +1,252 @@ | |||
1 | <?xml version="1.0"?> | ||
2 | <?xml-stylesheet href="chrome://global/skin/" type="text/css"?> | ||
3 | <?xml-stylesheet href="fireflix.css" type="text/css"?> | ||
4 | <!DOCTYPE page SYSTEM "chrome://fireflix/locale/fireflix.dtd"> | ||
5 | <page | ||
6 | xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" | ||
7 | id="fireflixwindow" title="Fireflix" | ||
8 | onload="fireflix.init()" | ||
9 | orient="vertical" | ||
10 | ondragover="nsDragAndDrop.dragOver(event,fireflix.uploadObserver)" | ||
11 | ondragdrop="nsDragAndDrop.drop(event,fireflix.uploadObserver)" | ||
12 | > | ||
13 | |||
14 | <script src="chrome://global/content/nsDragAndDrop.js"/> | ||
15 | <script src="chrome://global/content/nsTransferable.js"/> | ||
16 | <script type="application/x-javascript" src="md5.js" /> | ||
17 | <script type="application/x-javascript" src="flickr.js" /> | ||
18 | <script type="application/x-javascript" src="fireflix.js" /> | ||
19 | |||
20 | <stringbundleset> | ||
21 | <stringbundle id="loc_strings" src="chrome://fireflix/locale/fireflix.properties" /> | ||
22 | </stringbundleset> | ||
23 | |||
24 | <commandset id="cmdset_search"> | ||
25 | <command id="cmd_search" label="&panel.search.cmd_search.label;" | ||
26 | oncommand="fireflix.foundphotos.search_photos()"/> | ||
27 | <command id="cmd_search_open" label="&panel.search.cmd_search_open.label;" | ||
28 | oncommand="fireflix.foundphotos.on_cmd_open(event)" /> | ||
29 | </commandset> | ||
30 | |||
31 | <commandset id="cmdset_sets"> | ||
32 | <command id="cmd_refresh_sets" label="&panel.sets.cmd_refresh_sets;" | ||
33 | oncommand="fireflix.on_refresh_sets()" /> | ||
34 | <command id="cmd_set_props" label="&panel.sets.cmd_properties;" | ||
35 | oncommand="fireflix.on_set_props()" disabled="true" /> | ||
36 | </commandset> | ||
37 | |||
38 | <popupset> | ||
39 | <popup id="sets_menu"> | ||
40 | <menuitem command="cmd_set_props"/> | ||
41 | <menuitem command="cmd_refresh_sets"/> | ||
42 | <menuseparator/> | ||
43 | <menu label="&panel.sets.generate_html;" id="sets_html_menu"/> | ||
44 | </popup> | ||
45 | </popupset> | ||
46 | |||
47 | <commandset id="cmdset_uploads"> | ||
48 | <command id="cmd_uploads_clear" label="&panel.uploads.clear.label;" | ||
49 | oncommand="fireflix.uploads.on_clear()" /> | ||
50 | <command id="cmd_uploads_upload" label="&panel.uploads.upload.label;" | ||
51 | oncommand="fireflix.uploads.on_upload()" /> | ||
52 | <command id="cmd_uploads_remove" label="&panel.uploads.remove.label;" | ||
53 | oncommand="fireflix.uploads.on_remove()" /> | ||
54 | <command id="cmd_uploads_add" label="&panel.uploads.add.label;" | ||
55 | oncommand="fireflix.uploads.on_add()" /> | ||
56 | </commandset> | ||
57 | |||
58 | <popupset> | ||
59 | <popup id="uploads_menu"> | ||
60 | <menuitem command="cmd_uploads_add"/> | ||
61 | <menuitem command="cmd_uploads_clear"/> | ||
62 | <menuitem command="cmd_uploads_remove"/> | ||
63 | <menuseparator/> | ||
64 | <menuitem command="cmd_uploads_upload"/> | ||
65 | <menuseparator/> | ||
66 | <menu label="&panel.uploads.generate_html;" id="uploads_html_menu"/> | ||
67 | </popup> | ||
68 | </popupset> | ||
69 | |||
70 | <vbox class="wholething" flex="1"> | ||
71 | |||
72 | <groupbox> | ||
73 | <caption label="&panel.auth_info;"/> | ||
74 | <hbox> | ||
75 | <label id="auth_info" value="&panel.no_auth_info;" flex="1" disabled="true"/> | ||
76 | <button id="b_auth" label="&panel.auth_button;" oncommand="fireflix.on_auth()"/> | ||
77 | <button id="b_auth_done" label="&panel.auth_complete_button;" hidden="true" | ||
78 | oncommand="fireflix.on_auth_done()"/> | ||
79 | <button label="&panel.flickr_button.label;" | ||
80 | tooltiptext="&panel.flickr_button.tip;" | ||
81 | oncommand="fireflix.openTab('http://www.flickr.com/')" /> | ||
82 | </hbox> | ||
83 | </groupbox> | ||
84 | |||
85 | <tabbox flex="1" id="fireflix_tabs"> | ||
86 | |||
87 | <tabs> | ||
88 | <tab label="&panel.tabs.search;"/> | ||
89 | <tab label="&panel.tabs.sets;"/> | ||
90 | <tab label="&panel.tabs.tags;" hidden="true"/> <!-- TODO: --> | ||
91 | <tab id="tab_upload" label="&panel.tabs.upload;"/> | ||
92 | </tabs> | ||
93 | |||
94 | <tabpanels flex="1"> | ||
95 | |||
96 | <tabpanel id="tabpanel_search" flex="1"> | ||
97 | <vbox flex="1"> | ||
98 | <groupbox class="search_params" orient="vertical" onkeypress="if(event.keyCode==event.DOM_VK_RETURN) fireflix.foundphotos.search_photos()"> | ||
99 | <hbox> | ||
100 | <label control="search_for" value="&panel.search.search_for.label;" | ||
101 | accesskey="s"/> | ||
102 | <textbox id="search_for" flex="1"/> | ||
103 | </hbox> | ||
104 | <hbox> | ||
105 | <checkbox id="search_tags" label="&panel.search.mode.tagsonly.label;" | ||
106 | tooltiptext="&panel.search.mode.tagsonly.tip;" checked="false" | ||
107 | accesskey="t" /> | ||
108 | <checkbox id="search_mine" label="&panel.search.mode.mine.label;" checked="true" accesskey="m"/> | ||
109 | <spacer flex="1"/> | ||
110 | <button command="cmd_search"/> | ||
111 | </hbox> | ||
112 | </groupbox> | ||
113 | <tree id="searchresults" rows="4" flex="1" | ||
114 | onselect="fireflix.foundphotos.on_select()" | ||
115 | ondblclick="fireflix.foundphotos.on_cmd_open(event)" | ||
116 | onkeypress="if(event.keyCode==event.DOM_VK_RETURN) | ||
117 | fireflix.foundphotos.on_cmd_open(event)"> | ||
118 | <treecols> | ||
119 | <treecol id="sr_title" label="&panel.search.col.title.label;" flex="2" crop="end" align="start" /> | ||
120 | </treecols> | ||
121 | <treechildren/> | ||
122 | </tree> | ||
123 | <groupbox id="searchresult_props" orient="horizontal" hidden="true"> | ||
124 | <vbox width="100" pack="center"> | ||
125 | <hbox pack="center"> | ||
126 | <image id="search_photo"/> | ||
127 | </hbox> | ||
128 | </vbox> | ||
129 | <vbox flex="1"> | ||
130 | <label id="searchresult_title"/> | ||
131 | <textbox flex="1" multiline="true" class="plain" readonly="true" id="searchresult_description"/> | ||
132 | <hbox pack="end"> | ||
133 | <button command="cmd_search_open"/> | ||
134 | </hbox> | ||
135 | </vbox> | ||
136 | </groupbox> | ||
137 | </vbox> | ||
138 | </tabpanel> | ||
139 | |||
140 | <tabpanel id="tabpanel_sets" flex="1" | ||
141 | onkeypress="if(event.keyCode==event.DOM_VK_RETURN) | ||
142 | document.getElementById('setphotos').focus()"> | ||
143 | <vbox flex="1"> | ||
144 | <tree id="setslist" rows="4" onselect="fireflix.photosets.on_select()" | ||
145 | flex="1" context="sets_menu" | ||
146 | > | ||
147 | <treecols> | ||
148 | <treecol id="sl_name" label="&panel.sets.name.label;" flex="4" crop="end" align="start" tooltiptext="&panel.sets.name.tip;"/> | ||
149 | <splitter class="tree-splitter" /> | ||
150 | <treecol id="sl_photos" label="&panel.sets.photos.label;" flex="1" align="end" tooltiptext="&panel.sets.photos.tip;" /> | ||
151 | </treecols> | ||
152 | <treechildren/> | ||
153 | </tree> | ||
154 | <hbox> | ||
155 | <button command="cmd_refresh_sets" /> | ||
156 | <button command="cmd_set_props" /> | ||
157 | </hbox> | ||
158 | <tree id="setphotos" rows="4" onselect="fireflix.photoset.on_select()" | ||
159 | flex="1"> | ||
160 | <treecols> | ||
161 | <treecol id="sp_title" label="&panel.setphotos.title.label;" flex="1" crop="end" align="start" tooltiptext="&panel.setphotos.title.tip;" /> | ||
162 | <splitter class="tree-splitter" /> | ||
163 | <treecol id="sp_taken" label="&panel.setphotos.taken.label;" crop="end" align="start" tooltiptext="&panel.setphotos.taken.tip;" hidden="true" /> | ||
164 | <treecol id="sp_upload" label="&panel.setphotos.upload.label;" crop="end" align="start" tooltiptext="&panel.setphotos.upload.tip;" hidden="true" /> | ||
165 | </treecols> | ||
166 | <treechildren/> | ||
167 | </tree> | ||
168 | <groupbox id="set_photo_props" orient="horizontal"> | ||
169 | <vbox width="100" pack="center"> | ||
170 | <hbox pack="center"> | ||
171 | <image id="set_photo" hidden="true"/> | ||
172 | </hbox> | ||
173 | </vbox> | ||
174 | <spacer flex="1"/> | ||
175 | </groupbox> | ||
176 | </vbox> | ||
177 | </tabpanel> | ||
178 | |||
179 | <tabpanel id="tabpanel_tags"> | ||
180 | <listbox id="tagslist" rows="8" flex="1"> | ||
181 | <listhead> | ||
182 | <listheader label="&panel.tagslist.tag.label;"/> | ||
183 | </listhead> | ||
184 | <listcols> | ||
185 | <listcol flex="1"/> | ||
186 | </listcols> | ||
187 | </listbox> | ||
188 | </tabpanel> | ||
189 | |||
190 | <tabpanel id="tabpanel_upload"> | ||
191 | <vbox flex="1"> | ||
192 | <tree id="uploadlist" rows="8" flex="1" | ||
193 | onselect="fireflix.uploads.selectionChanged()" | ||
194 | context="uploads_menu"> | ||
195 | <treecols> | ||
196 | <treecol id="up_file" label="&panel.uploadlist.file.label;" flex="4" crop="start" align="start"/> | ||
197 | <splitter class="tree-splitter" /> | ||
198 | <treecol id="up_title" label="&panel.uploadlist.title.label;" flex="5" crop="end" align="start" /> | ||
199 | <splitter class="tree-splitter" /> | ||
200 | <treecol id="up_status" label="&panel.uploadlist.status.label;" flex="1" crop="end" align="start" /> | ||
201 | </treecols> | ||
202 | <treechildren/> | ||
203 | </tree> | ||
204 | <progressmeter id="upload_progress" mode="undetermined" hidden="true" /> | ||
205 | <groupbox id="upload_file_props" orient="horizontal" hidden="true"> | ||
206 | <image id="upload_file_preview" width="100" height="100" /> | ||
207 | <grid flex="1"> | ||
208 | <columns> | ||
209 | <column/> | ||
210 | <column flex="1"/> | ||
211 | </columns> | ||
212 | <rows> | ||
213 | <row> | ||
214 | <label control="upload_filename" | ||
215 | value="&panel.upload_props.filename.label;" /> | ||
216 | <textbox id="upload_filename" | ||
217 | oninput="fireflix.uploads.propsToSel('filename')"/> | ||
218 | </row> | ||
219 | <row> | ||
220 | <label control="upload_title" value="&panel.upload_props.title.label;" /> | ||
221 | <textbox id="upload_title" | ||
222 | oninput="fireflix.uploads.propsToSel('title')"/> | ||
223 | </row> | ||
224 | <row> | ||
225 | <label control="uplod_tags" value="&panel.upload_props.tags.label;" /> | ||
226 | <textbox id="upload_tags" | ||
227 | oninput="fireflix.uploads.propsToSel('tags')"/> | ||
228 | </row> | ||
229 | <!-- TODO: description, public, friend, family --> | ||
230 | </rows> | ||
231 | </grid> | ||
232 | </groupbox> | ||
233 | <hbox> | ||
234 | <button command="cmd_uploads_add" /> | ||
235 | <spacer flex="1"/> | ||
236 | <button command="cmd_uploads_remove" /> | ||
237 | <spacer flex="1"/> | ||
238 | <button command="cmd_uploads_clear" /> | ||
239 | </hbox> | ||
240 | <hbox pack="center"> | ||
241 | <button command="cmd_uploads_upload" flex="1"/> | ||
242 | </hbox> | ||
243 | </vbox> | ||
244 | </tabpanel> | ||
245 | |||
246 | </tabpanels> | ||
247 | |||
248 | </tabbox> | ||
249 | |||
250 | </vbox> | ||
251 | |||
252 | </page> | ||
diff --git a/content/fireflix.css b/content/fireflix.css new file mode 100644 index 0000000..188f48e --- a/dev/null +++ b/content/fireflix.css | |||
@@ -0,0 +1,90 @@ | |||
1 | .generated.wholething, | ||
2 | .about.wholething, | ||
3 | tabbox, tabpanels, tabpanel { | ||
4 | background: url("background.jpeg"); | ||
5 | } | ||
6 | tabpanels { | ||
7 | padding: 0px; | ||
8 | } | ||
9 | |||
10 | tree { | ||
11 | margin-top: 2px; | ||
12 | background: rgb(12,167,0); | ||
13 | color: rgb(255,255,0); | ||
14 | font-size: 90%; | ||
15 | } | ||
16 | tree treechildren { /* for windows */ | ||
17 | background: rgb(12,167,0); | ||
18 | } | ||
19 | |||
20 | tree#uploadlist treechildren::-moz-tree-cell-text(pending) { | ||
21 | } | ||
22 | tree#uploadlist treechildren::-moz-tree-cell-text(completed) { | ||
23 | color: white; | ||
24 | } | ||
25 | tree#uploadlist treechildren::-moz-tree-row(failed) { | ||
26 | background: yellow; | ||
27 | } | ||
28 | tree#uploadlist treechildren::-moz-tree-cell-text(failed) { | ||
29 | color: red; | ||
30 | } | ||
31 | tree#uploadlist treechildren::-moz-tree-cell-text(uploading) { | ||
32 | font-weight: bold; | ||
33 | } | ||
34 | |||
35 | groupbox#searchresult_props, | ||
36 | groupbox.search_params, | ||
37 | groupbox#upload_file_props, | ||
38 | groupbox#set_props, | ||
39 | groupbox#set_photo_props { | ||
40 | background: white; | ||
41 | } | ||
42 | |||
43 | groupbox#upload_file_props label { | ||
44 | text-align: right; | ||
45 | } | ||
46 | |||
47 | image#set_photo, image#set_primary { | ||
48 | border: black 1px solid; | ||
49 | } | ||
50 | |||
51 | .about .insides { | ||
52 | margin: 1ex; | ||
53 | } | ||
54 | .about .text { | ||
55 | border: yellow solid 1px; | ||
56 | background: green; | ||
57 | } | ||
58 | .about .title { | ||
59 | font-size: 300%; | ||
60 | font-weight: bold; | ||
61 | color: yellow; | ||
62 | } | ||
63 | .about .link { | ||
64 | text-decoration: underline; | ||
65 | color: white; | ||
66 | cursor: pointer; | ||
67 | } | ||
68 | |||
69 | menuitem.menuhead { | ||
70 | background: gray; | ||
71 | color: black; | ||
72 | font-weight: bold; | ||
73 | } | ||
74 | |||
75 | label#searchresult_description { | ||
76 | font-weight: bold; | ||
77 | } | ||
78 | textbox#searchresult_description { | ||
79 | padding: 1px 3px !important; | ||
80 | background: white; | ||
81 | } | ||
82 | |||
83 | #copying div { | ||
84 | margin: 1ex 1em; | ||
85 | font-family: courier, monospace; | ||
86 | font-size: 9pt; | ||
87 | padding: 2px; | ||
88 | border: dotted 1px gray; | ||
89 | background: white; | ||
90 | } | ||
diff --git a/content/fireflix.js b/content/fireflix.js new file mode 100644 index 0000000..9518480 --- a/dev/null +++ b/content/fireflix.js | |||
@@ -0,0 +1,878 @@ | |||
1 | function splitascii(s) { | ||
2 | var rv=''; | ||
3 | for(var i=0;i<s.length;++i) { | ||
4 | var w = s.charCodeAt(i); | ||
5 | rv += String.fromCharCode( | ||
6 | w&0xff, (w>>8)&0xff ); | ||
7 | } | ||
8 | return rv; | ||
9 | } | ||
10 | |||
11 | |||
12 | var fireflix = { | ||
13 | flickr: new Flickr(), | ||
14 | init: function() { | ||
15 | this.loc_strings = document.getElementById('loc_strings'); | ||
16 | this.build_menus(); | ||
17 | this.cmd_set_props = document.getElementById('cmd_set_props'); | ||
18 | this.foundphotos.init(this); | ||
19 | this.photosets.init(this); | ||
20 | this.photoset.init(this); | ||
21 | this.uploads.init(this); | ||
22 | this.uploadObserver.init(this); | ||
23 | this.flickr.api_key = '9c43cd66947a57e6f29db1a9da3f72e3'; | ||
24 | this.flickr.api_shs = '9c33c9e2f0f0cfd5'; | ||
25 | this.flickr.prefs_root = 'net.klever.kin.fireflix'; | ||
26 | this.flickr.load_token(); | ||
27 | document.getElementById('setslist').view = this.photosets; | ||
28 | document.getElementById('setphotos').view = this.photoset; | ||
29 | document.getElementById('uploadlist').view = this.uploads; | ||
30 | this.flickr.no_auth_info_label = document.getElementById('auth_info').value; | ||
31 | if(this.flickr.token) { | ||
32 | this.refresh_stuff(); | ||
33 | document.getElementById('auth_info').value = | ||
34 | this.flickr.user.fullname+' ['+this.flickr.user.username+']'; | ||
35 | document.getElementById('auth_info').disabled = false; | ||
36 | document.getElementById('b_auth').hidden = true; | ||
37 | } | ||
38 | }, | ||
39 | on_auth: function() { | ||
40 | var _this = this; | ||
41 | this.flickr.authorize_0( | ||
42 | function() { | ||
43 | document.getElementById('b_auth').hidden = true; | ||
44 | document.getElementById('b_auth_done').hidden = false; | ||
45 | }, function(x,s,c,m) { | ||
46 | _this.flickr_failure(x,s,c,m); | ||
47 | } | ||
48 | ); | ||
49 | }, | ||
50 | on_auth_done: function() { | ||
51 | document.getElementById('b_auth_done').hidden = true; | ||
52 | var _this = this; | ||
53 | this.flickr.authorize_1( | ||
54 | function() { | ||
55 | _this.flickr.save_token(); | ||
56 | _this.refresh_stuff(); | ||
57 | document.getElementById('auth_info').value = | ||
58 | _this.flickr.user.fullname+' ['+_this.flickr.user.username+']'; | ||
59 | document.getElementById('auth_info').disabled = false; | ||
60 | }, function(x,s,c,m) { | ||
61 | document.getElementById('b_auth').hidden = false; | ||
62 | _this.flickr_failure(x,s,c,m); | ||
63 | } | ||
64 | ); | ||
65 | }, | ||
66 | |||
67 | refresh_sets: function() { this.photosets.refresh_sets(); }, | ||
68 | refresh_stuff: function() { | ||
69 | this.refresh_sets(); | ||
70 | this.refresh_user_tags(); | ||
71 | }, | ||
72 | |||
73 | /* photoset treeview */ | ||
74 | photoset: { | ||
75 | photos: new Array(), | ||
76 | fireflix: null, | ||
77 | init: function(f) { | ||
78 | this.fireflix = f; | ||
79 | }, | ||
80 | rowCount: 0, | ||
81 | getCellText: function(r,c) { | ||
82 | var p = this.photos[r]; | ||
83 | if(c.id=='sp_title') return p.title; | ||
84 | if(c.id=='sp_taken') return p.datetaken; | ||
85 | if(c.id=='sp_upload') return p.dateupload; /* TODO: unixtime conversion */ | ||
86 | return c.id; | ||
87 | }, | ||
88 | setTree: function(t) { this.tree = t }, | ||
89 | isContainer: function(r) { return false; }, | ||
90 | isSeparator: function(r) { return false; }, | ||
91 | isSorted: function(r) { return false; }, | ||
92 | getLevel: function(r) { return 0; }, | ||
93 | getImageSrc: function(r,c) { return null }, | ||
94 | getRowProperties: function(r,p) {}, | ||
95 | getCellProperties: function(cid,cel,p) {}, | ||
96 | getColumnProperties: function(cid,cel,p) { }, | ||
97 | cycleHeader: function(cid,e) { }, | ||
98 | getParentIndex: function(r) { return -1; }, | ||
99 | drop: function(r,o) { }, | ||
100 | canDropBeforeAfter: function(r,b) { return false }, | ||
101 | |||
102 | importXPR: function(xp) { | ||
103 | this.tree.beginUpdateBatch(); | ||
104 | this.photos = new Array(); | ||
105 | var n; while(n=xp.iterateNext()) { | ||
106 | this.photos.push(new Photo(n)); | ||
107 | } | ||
108 | this.rowCount = this.photos.length; | ||
109 | this.tree.endUpdateBatch(); | ||
110 | }, | ||
111 | load_photos: function(psid) { | ||
112 | var _this = this; | ||
113 | this.fireflix.flickr.api_call( | ||
114 | { | ||
115 | method: 'flickr.photosets.getPhotos', | ||
116 | auth_token: 'default', | ||
117 | photoset_id: psid, | ||
118 | extras: 'license,date_upload,date_taken,owner_name,icon_server,original_format,last_update' | ||
119 | }, function(xr) { | ||
120 | var x = xr.responseXML; | ||
121 | var xp = x.evaluate( | ||
122 | '/rsp/photoset/photo', x, null, | ||
123 | XPathResult.ORDERED_NODE_ITERATOR_TYPE, null ); | ||
124 | _this.importXPR(xp); | ||
125 | }, function(x,s,c,m) { | ||
126 | _this.fireflix.flickr_failure(x,s,c,m); | ||
127 | } | ||
128 | ); | ||
129 | }, | ||
130 | on_select: function() { | ||
131 | if(this.selection.count==1) { | ||
132 | var p = this.photos[this.selection.currentIndex]; | ||
133 | document.getElementById('set_photo').src = | ||
134 | this.fireflix.flickr.get_photo_url(p.server,p.id,p.secret,'t'); | ||
135 | document.getElementById('set_photo').hidden = false; | ||
136 | }else{ | ||
137 | document.getElementById('set_photo').hidden = true; | ||
138 | } | ||
139 | } | ||
140 | }, | ||
141 | |||
142 | /* photosets treeview */ | ||
143 | photosets: { | ||
144 | sets: new Array(), | ||
145 | fireflix: null, | ||
146 | init: function(f) { | ||
147 | this.fireflix = f; | ||
148 | }, | ||
149 | rowCount: 0, | ||
150 | getCellText: function(r,c) { | ||
151 | var s = this.sets[r]; | ||
152 | if(c.id=='sl_name') return s.title; | ||
153 | if(c.id=='sl_photos') return s.photos; | ||
154 | return c.id; | ||
155 | }, | ||
156 | setTree: function(t) { this.tree = t }, | ||
157 | isContainer: function(r) { return false; }, | ||
158 | isSeparator: function(r) { return false; }, | ||
159 | isSorted: function() { return false; }, | ||
160 | getLevel: function(r) { return 0; }, | ||
161 | getImageSrc: function(r,c) { return null }, | ||
162 | getRowProperties: function(r,p) {}, | ||
163 | getCellProperties: function(cid,cel,p) { }, | ||
164 | getColumnProperties: function(cid,cel,p) { }, | ||
165 | cycleHeader: function(cid,e) { }, | ||
166 | getParentIndex: function(r) { return -1; }, | ||
167 | drop: function(r,o) { }, | ||
168 | canDropBeforeAfter: function(r,b) { return false }, | ||
169 | |||
170 | importXPR: function(xp) { | ||
171 | this.tree.beginUpdateBatch(); | ||
172 | this.sets = new Array(); | ||
173 | var n; while(n=xp.iterateNext()) { | ||
174 | this.sets.push(new Photoset(n)); | ||
175 | } | ||
176 | this.rowCount = this.sets.length; | ||
177 | this.tree.endUpdateBatch(); | ||
178 | }, | ||
179 | refresh_sets: function() { | ||
180 | var _this = this; | ||
181 | this.fireflix.flickr.api_call( | ||
182 | { | ||
183 | method: 'flickr.photosets.getList', | ||
184 | auth_token: 'default' | ||
185 | }, function(xr) { | ||
186 | var x = xr.responseXML; | ||
187 | var xp = x.evaluate( | ||
188 | '/rsp/photosets/photoset', x, null, | ||
189 | XPathResult.ORDERED_NODE_ITERATOR_TYPE, null ); | ||
190 | _this.importXPR(xp); | ||
191 | }, function(x,s,c,m) { | ||
192 | _this.fireflix.flickr_failure(x,s,c,m); | ||
193 | } | ||
194 | ); | ||
195 | }, | ||
196 | on_select: function() { | ||
197 | if(this.selection.count==1) { | ||
198 | this.fireflix.cmd_set_props.setAttribute('disabled','false'); | ||
199 | var s = this.sets[this.selection.currentIndex]; | ||
200 | this.fireflix.photoset.load_photos(s.id); | ||
201 | }else{ | ||
202 | this.fireflix.cmd_set_props.setAttribute('disabled','true'); | ||
203 | } | ||
204 | } | ||
205 | }, | ||
206 | |||
207 | refresh_user_tags: function() { | ||
208 | var lb = document.getElementById('tagslist'); | ||
209 | var _this = this; | ||
210 | this.flickr.api_call( | ||
211 | { | ||
212 | method: 'flickr.tags.getListUser', | ||
213 | auth_token: 'default', | ||
214 | }, function(xr) { | ||
215 | var x = xr.responseXML; | ||
216 | var xp = x.evaluate( | ||
217 | '/rsp/who/tags/tag', x, null, | ||
218 | XPathResult.ORDERED_NODE_ITERATOR_TYPE, null ); | ||
219 | // TODO: clear list | ||
220 | var n; while(n=xp.iterateNext()) { | ||
221 | lb.appendItem(n.firstChild.nodeValue); | ||
222 | } | ||
223 | }, function(x,s,c,m) { | ||
224 | _this.flickr_failure(x,s,c,m); | ||
225 | } | ||
226 | ); | ||
227 | }, | ||
228 | |||
229 | uploadObserver: { | ||
230 | fireflix: null, | ||
231 | init: function(f) { | ||
232 | this.fireflix = f; | ||
233 | }, | ||
234 | getSupportedFlavours: function() { | ||
235 | var rv = new FlavourSet(); | ||
236 | rv.appendFlavour('application/x-moz-file','nsIFile'); | ||
237 | rv.appendFlavour('application/x-moz-url'); | ||
238 | rv.appendFlavour('text/uri-list'); | ||
239 | rv.appendFlavour('text/unicode'); | ||
240 | return rv; | ||
241 | }, | ||
242 | canHandleMultipleItems: true, | ||
243 | onDragOver: function(ev,fl,sess) { | ||
244 | return true; | ||
245 | }, | ||
246 | onDrop: function(ev,dd,s) { | ||
247 | var ldf = null; | ||
248 | for(var i in dd.dataList) { | ||
249 | var di = dd.dataList[i]; | ||
250 | var dif = di.first; | ||
251 | if( | ||
252 | ldf==null | ||
253 | || ldf.flavour.contentType!=dif.flavour.contentType | ||
254 | || ldf.contentLength!=dif.contentLength | ||
255 | || ldf.data!=dif.data ) | ||
256 | this.drop_item(ev,di,s); | ||
257 | ldf = dif; | ||
258 | } | ||
259 | }, | ||
260 | drop_item: function(ev,di,s) { | ||
261 | var d = di.first; | ||
262 | switch(d.flavour.contentType) { | ||
263 | case 'text/unicode': | ||
264 | this.drop_urilist(ev,d.data,s); | ||
265 | break; | ||
266 | case 'application/x-moz-file': | ||
267 | this.fireflix.uploads.add(d.data.path); | ||
268 | document.getElementById('fireflix_tabs').selectedTab | ||
269 | = document.getElementById('tab_upload'); | ||
270 | break; | ||
271 | case 'text/uri-list': | ||
272 | // is it ascii or could it be utf8? | ||
273 | this.drop_urilist(ev,splitascii(d.data),s); | ||
274 | break; | ||
275 | default: alert(d.flavour.contentType+':'+d.data); break; | ||
276 | }; | ||
277 | }, | ||
278 | drop_urilist: function(ev,ul,s) { | ||
279 | // TODO: check for being a file? | ||
280 | var us = decodeURIComponent(ul).split(/[\r\n]/); | ||
281 | for(var ui in us) | ||
282 | if(/\S/.test(us[ui])) | ||
283 | this.fireflix.uploads.add(us[ui]); | ||
284 | document.getElementById('fireflix_tabs').selectedTab | ||
285 | = document.getElementById('tab_upload'); | ||
286 | } | ||
287 | }, | ||
288 | |||
289 | uploads: { | ||
290 | fireflix: null, | ||
291 | init: function(f) { | ||
292 | this.fireflix=f; | ||
293 | this.upload_filename = document.getElementById('upload_filename'); | ||
294 | this.upload_title = document.getElementById('upload_title'); | ||
295 | this.upload_file_preview = document.getElementById('upload_file_preview'); | ||
296 | this.upload_file_props = document.getElementById('upload_file_props'); | ||
297 | this.upload_progress = document.getElementById('upload_progress'); | ||
298 | this.upload_tags = document.getElementById('upload_tags'); | ||
299 | }, | ||
300 | files: new Array(), | ||
301 | rowCount: 0, | ||
302 | getCellText: function(r,c) { | ||
303 | var f = this.files[r]; | ||
304 | if(c.id=='up_file') return f.file; | ||
305 | if(c.id=='up_title') return f.title; | ||
306 | if(c.id=='up_status') return f.state; | ||
307 | return c.id; | ||
308 | }, | ||
309 | setTree: function(t) { this.tree = t }, | ||
310 | isContainer: function(r) { return false; }, | ||
311 | isSeparator: function(r) { return false; }, | ||
312 | isSorted: function(r) { return false; }, | ||
313 | getLevel: function(r) { return 0; }, | ||
314 | getImageSrc: function(r,c) { return null }, | ||
315 | getRowProperties: function(r,p) { | ||
316 | try { | ||
317 | if(!Components) return; | ||
318 | }catch(e) { return } | ||
319 | var f = this.files[r]; | ||
320 | var as = Components.classes['@mozilla.org/atom-service;1']. | ||
321 | getService(Components.interfaces.nsIAtomService); | ||
322 | p.AppendElement(as.getAtom(f.state)); | ||
323 | }, | ||
324 | getCellProperties: function(r,c,p) { this.getRowProperties(r,p); }, | ||
325 | getColumnProperties: function(c,p) { }, | ||
326 | cycleHeader: function(cid,e) { }, | ||
327 | getParentIndex: function(r) { return -1; }, | ||
328 | drop: function(r,o) { }, | ||
329 | canDropBeforeAfter: function(r,b) { return false }, | ||
330 | |||
331 | add: function(f) { | ||
332 | if(f.indexOf('file:/')==0) { | ||
333 | f = f.substr(5); | ||
334 | while(f.substr(0,2)=='//') { // XXX: not very performant, is it? ;-) | ||
335 | f = f.substr(1); | ||
336 | } | ||
337 | } | ||
338 | var t = f; | ||
339 | var ls = t.lastIndexOf('/'); | ||
340 | if(ls>0) t = t.substr(ls+1); | ||
341 | ls = t.lastIndexOf('\\'); | ||
342 | if(ls>0) t = t.substr(ls+1); | ||
343 | var ld = t.lastIndexOf('.'); | ||
344 | if(ld>0) t = t.substr(0,ld); | ||
345 | this.files.push( { | ||
346 | file: f, | ||
347 | title: t, | ||
348 | tags: '', | ||
349 | state: 'pending' | ||
350 | } ); | ||
351 | this.rowCount = this.files.length; | ||
352 | this.tree.rowCountChanged(this.rowCount-1,1); | ||
353 | }, | ||
354 | |||
355 | upload_worker: function() { | ||
356 | for(var f in this.files) { | ||
357 | if(this.files[f].state=='pending') { | ||
358 | var ff = this.files[f]; | ||
359 | dump('upload '+ff.file+'\n'); | ||
360 | this.on_file_upload(ff); | ||
361 | ff.state='uploading'; | ||
362 | this.tree.invalidate(); | ||
363 | var _this = this; | ||
364 | this.fireflix.flickr.upload_file( | ||
365 | ff.file, { title: ff.title, tags: ff.tags }, | ||
366 | function(x,p) { | ||
367 | ff.photoid = p; | ||
368 | _this.batch_ids.push(p); | ||
369 | ff.state='completed'; | ||
370 | _this.tree.invalidate(); | ||
371 | window.setTimeout(_this.upload_to,0,_this); | ||
372 | }, function(x,s,c,m) { | ||
373 | ff.state='failed'; | ||
374 | ff.flickr_errcode = c; | ||
375 | ff.flickr_errmsg = m; | ||
376 | _this.tree.invalidate(); | ||
377 | window.setTimeout(_this.upload_to,0,_this); | ||
378 | } | ||
379 | ); | ||
380 | return; | ||
381 | } | ||
382 | } | ||
383 | dump('uploading done\n'); | ||
384 | this.on_finish_upload(); | ||
385 | }, | ||
386 | upload_to: function(_this) { _this.upload_worker(); }, | ||
387 | on_file_upload: function(f) { | ||
388 | document.getElementById('cmd_uploads_upload').setAttribute('disabled','true'); | ||
389 | for(var fi in this.files) { | ||
390 | if(this.files[fi].file==f.file) { | ||
391 | this.tree.ensureRowIsVisible(fi); | ||
392 | this.selection.rangedSelect(fi,fi,false); | ||
393 | this.selection.currentIndex = fi; | ||
394 | this.selToProps(); | ||
395 | break; | ||
396 | } | ||
397 | } | ||
398 | }, | ||
399 | on_finish_upload: function() { | ||
400 | if(this.batch_ids.length) { | ||
401 | var psn = prompt(this.fireflix.loc_strings.getString('postUploadPhotoset')); | ||
402 | if(psn!=null) { | ||
403 | var pids = this.batch_ids.join(','); | ||
404 | var ppid = this.batch_ids[0]; | ||
405 | var _this = this; | ||
406 | this.fireflix.flickr.api_call( | ||
407 | { | ||
408 | method: 'flickr.photosets.create', | ||
409 | auth_token: 'default', | ||
410 | title: psn, | ||
411 | primary_photo_id: ppid | ||
412 | }, function(x) { | ||
413 | var npid = | ||
414 | x.responseXML.getElementsByTagName('photoset').item(0).getAttribute('id'); | ||
415 | _this.fireflix.flickr.api_call( | ||
416 | { | ||
417 | method: 'flickr.photosets.editPhotos', | ||
418 | auth_token: 'default', | ||
419 | photoset_id: npid, | ||
420 | primary_photo_id: ppid, | ||
421 | photo_ids: pids | ||
422 | }, function(x) { | ||
423 | _this.fireflix.refresh_sets(); | ||
424 | }, function(x,s,c,m) { | ||
425 | _this.fireflix.flickr_failure(x,s,c,m); | ||
426 | } | ||
427 | ); | ||
428 | }, function(x,s,c,m) { | ||
429 | _this.fireflix.flickr_failure(x,s,c,m); | ||
430 | } | ||
431 | ); | ||
432 | } | ||
433 | } | ||
434 | this.selection.clearSelection(); | ||
435 | document.getElementById('cmd_uploads_upload').setAttribute('disabled','false'); | ||
436 | this.upload_progress.setAttribute('hidden','true'); | ||
437 | }, | ||
438 | |||
439 | clear_list: function() { | ||
440 | this.tree.beginUpdateBatch(); | ||
441 | this.rowCount = 0; | ||
442 | this.files = new Array(); | ||
443 | this.tree.endUpdateBatch(); | ||
444 | this.selToProps(); | ||
445 | }, | ||
446 | selectionChanged: function() { | ||
447 | this.selToProps(); | ||
448 | }, | ||
449 | disableProps: function() { | ||
450 | this.upload_filename.value=''; | ||
451 | this.upload_filename.disabled = true; | ||
452 | this.upload_title.value=''; | ||
453 | this.upload_title.disabled = true; | ||
454 | this.upload_file_preview.src = null; | ||
455 | this.upload_file_props.hidden = true; | ||
456 | this.upload_tags.value=''; | ||
457 | this.upload_tags.disabled = true; | ||
458 | }, | ||
459 | selToProps: function() { | ||
460 | if(!this.selection.count) { | ||
461 | this.disableProps(); | ||
462 | }else if(this.selection.count==1) { | ||
463 | var f=this.files[this.selection.currentIndex]; | ||
464 | if(f==null || f.state!='pending') { | ||
465 | this.disableProps(); | ||
466 | }else{ | ||
467 | this.upload_filename.value = f.file; | ||
468 | this.upload_filename.disabled = false; | ||
469 | this.upload_title.value = f.title; | ||
470 | this.upload_title.disabled = false; | ||
471 | this.upload_file_preview.src = 'file:///'+f.file; | ||
472 | this.upload_file_props.hidden = false; | ||
473 | this.upload_tags.value = f.tags; | ||
474 | this.upload_tags.disabled = false; | ||
475 | } | ||
476 | }else{ | ||
477 | var ftitle = null; var onetitle = true; | ||
478 | var ftags = null; var onetag = true; | ||
479 | var fs = 0; | ||
480 | for(var ff in this.files) { | ||
481 | if(this.selection.isSelected(ff) && this.files[ff].state=='pending' ) { | ||
482 | ++fs; | ||
483 | if(ftitle==null) { | ||
484 | ftitle = this.files[ff].title; | ||
485 | }else if(ftitle!=this.files[ff].title) { | ||
486 | onetitle = false; | ||
487 | } | ||
488 | if(ftags==null) { | ||
489 | ftags = this.files[ff].tags; | ||
490 | }else if(ftags!=this.files[ff].tags) { | ||
491 | onetag = false; | ||
492 | } | ||
493 | } | ||
494 | } | ||
495 | if(fs) { | ||
496 | this.upload_filename.value=''; | ||
497 | this.upload_filename.disabled = true; | ||
498 | if(onetitle) | ||
499 | this.upload_title.value = ftitle; | ||
500 | this.upload_title.disabled = false; | ||
501 | if(onetag) | ||
502 | this.upload_tags.value = ftags; | ||
503 | this.upload_tags.disabled = false; | ||
504 | this.upload_file_preview.src = null; | ||
505 | this.upload_file_props.hidden = false; | ||
506 | }else | ||
507 | this.disableProps(); | ||
508 | } | ||
509 | }, | ||
510 | propsToSel: function(prop) { | ||
511 | if(this.selection.count<=0) return; | ||
512 | for(var ff in this.files) { | ||
513 | if(this.selection.isSelected(ff) && this.files[ff].state=='pending') { | ||
514 | if(prop=='filename') | ||
515 | this.files[ff].file = this.upload_filename.value; | ||
516 | if(prop=='title') | ||
517 | this.files[ff].title = this.upload_title.value; | ||
518 | if(prop=='tags') | ||
519 | this.files[ff].tags = this.upload_tags.value; | ||
520 | this.tree.invalidateRow(ff); | ||
521 | } | ||
522 | } | ||
523 | }, | ||
524 | |||
525 | on_upload: function() { | ||
526 | this.selToProps(); | ||
527 | this.batch_ids = new Array(); | ||
528 | this.upload_progress.value=0; | ||
529 | this.upload_progress.setAttribute('hidden','false'); | ||
530 | this.upload_worker(); | ||
531 | }, | ||
532 | on_clear: function() { | ||
533 | this.clear_list(); | ||
534 | }, | ||
535 | on_remove: function() { | ||
536 | if(this.selection.count) { | ||
537 | this.tree.beginUpdateBatch(); | ||
538 | for(var i=this.files.length-1;i>=0;--i) { | ||
539 | if(this.selection.isSelected(i)) { | ||
540 | this.files.splice(i,1); | ||
541 | this.rowCount--; | ||
542 | } | ||
543 | } | ||
544 | this.tree.endUpdateBatch(); | ||
545 | this.selection.clearSelection(); | ||
546 | } | ||
547 | }, | ||
548 | on_add: function() { | ||
549 | var ifp = Components.interfaces.nsIFilePicker; | ||
550 | var fp = Components.classes["@mozilla.org/filepicker;1"].createInstance(ifp); | ||
551 | fp.init(window, "Select a File", ifp.modeOpenMultiple); | ||
552 | fp.appendFilters(ifp.filterImages); | ||
553 | var rv = fp.show(); | ||
554 | if(rv==ifp.returnOK) { | ||
555 | var ff = fp.files; | ||
556 | while(ff.hasMoreElements()) { | ||
557 | var f = ff.getNext(); | ||
558 | f.QueryInterface(Components.interfaces.nsIFile); | ||
559 | this.add(f.path); | ||
560 | } | ||
561 | } | ||
562 | } | ||
563 | }, | ||
564 | |||
565 | on_set_props: function() { | ||
566 | var pset = this.photosets.sets[this.photosets.selection.currentIndex]; | ||
567 | window.openDialog( | ||
568 | "chrome://fireflix/content/photoset-props.xul", | ||
569 | null, "dependent,modal,dialog,chrome", this, | ||
570 | pset ); | ||
571 | if(pset.dirty) { | ||
572 | var _this = this; | ||
573 | this.flickr.api_call( | ||
574 | { | ||
575 | method: 'flickr.photosets.editMeta', | ||
576 | auth_token: 'default', | ||
577 | photoset_id: pset.id, | ||
578 | title: pset.title, | ||
579 | description: pset.description | ||
580 | }, function(xr) { | ||
581 | pset.dirty = false; | ||
582 | _this.flickr.api_call( | ||
583 | { | ||
584 | method: 'flickr.photosets.getPhotos', | ||
585 | auth_token: 'default', | ||
586 | photoset_id: pset.id | ||
587 | }, function(xr) { | ||
588 | var x = xr.responseXML; | ||
589 | var xp = x.evaluate( | ||
590 | '/rsp/photoset/photo', x, null, | ||
591 | XPathResult.ORDERED_NODE_ITERATOR_TYPE, null ); | ||
592 | var phids = new Array(); | ||
593 | var priph = null; | ||
594 | var n; while(n=xp.iterateNext()) { | ||
595 | var pid = n.getAttribute('id'); | ||
596 | phids.push( pid ); | ||
597 | if(pid==pset.primary && n.getAttribute('isprimary')!='1') | ||
598 | priph = pid; | ||
599 | } | ||
600 | if(priph) { | ||
601 | _this.flickr.api_call( | ||
602 | { | ||
603 | method: 'flickr.photosets.editPhotos', | ||
604 | auth_token: 'default', | ||
605 | photoset_id: pset.id, | ||
606 | primary_photo_id: priph, | ||
607 | photo_ids: phids.join(',') | ||
608 | }, function() { }, function(x,s,c,m) { /* flickr.photosets.editPhotos */ | ||
609 | _this.flickr_failure(x,s,c,m); | ||
610 | } | ||
611 | ); | ||
612 | } | ||
613 | }, function(x,s,c,m) { /* flickr.photosets.getPhotos */ | ||
614 | _this.flickr_failure(x,s,c,m); | ||
615 | } | ||
616 | ); | ||
617 | }, function(x,s,c,m) { /* flickr.photosets.editMeta */ | ||
618 | _this.flickr_failure(x,s,c,m); | ||
619 | } | ||
620 | ); | ||
621 | } | ||
622 | }, | ||
623 | on_refresh_sets: function() { | ||
624 | this.refresh_sets(); | ||
625 | }, | ||
626 | on_cmd_sets_html: function(csfx,ev) { | ||
627 | var uti = csfx.charAt(0); var utl = csfx.charAt(1); | ||
628 | var rv = this.build_html(this.photoset.photos,uti,utl); | ||
629 | this.popup_content(rv); | ||
630 | }, | ||
631 | |||
632 | on_cmd_uploads_html: function(csfx,ev) { | ||
633 | var uti = csfx.charAt(0); var utl = csfx.charAt(1); | ||
634 | var pids = new Array(); | ||
635 | for(var f in this.uploads.files) { | ||
636 | if(this.uploads.selection.isSelected(f)) | ||
637 | if(this.uploads.files[f].photoid) | ||
638 | pids.push(this.uploads.files[f].photoid); | ||
639 | } | ||
640 | var pp = this.uploads.rowCount*2; if(pp>500) pp = 500; | ||
641 | var _this = this; | ||
642 | this.flickr.api_call( | ||
643 | { | ||
644 | method: 'flickr.photos.search', | ||
645 | auth_token: 'default', | ||
646 | extras: 'original_format', | ||
647 | user_id: 'me', | ||
648 | per_page: pp | ||
649 | }, | ||
650 | function(xr) { | ||
651 | var x = xr.responseXML; | ||
652 | var rv = ''; | ||
653 | for(var pn in pids) { | ||
654 | var p = pids[pn]; | ||
655 | var pp = new Photo(xp_node('/rsp/photos/photo[@id='+p+']',x)); | ||
656 | rv += _this.photo_html(pp,uti,utl)+'\n'; | ||
657 | } | ||
658 | _this.popup_content(rv); | ||
659 | }, function(x,s,c,m) { | ||
660 | _this.flickr_failure(x,s,c,m); | ||
661 | } | ||
662 | ); | ||
663 | }, | ||
664 | |||
665 | /* | ||
666 | * | ||
667 | */ | ||
668 | foundphotos: { | ||
669 | fireflix: null, | ||
670 | init: function(f) { | ||
671 | this.fireflix = f; | ||
672 | this.search_for = document.getElementById('search_for'); | ||
673 | this.search_tags= document.getElementById('search_tags'); | ||
674 | this.search_mine = document.getElementById('search_mine'); | ||
675 | document.getElementById('searchresults').view = this; | ||
676 | this.searchresult_props = document.getElementById('searchresult_props'); | ||
677 | this.search_photo = document.getElementById('search_photo'); | ||
678 | this.searchresult_title = document.getElementById('searchresult_title'); | ||
679 | this.searchresult_description = document.getElementById('searchresult_description'); | ||
680 | }, | ||
681 | photos: new Array(), | ||
682 | rowCount: 0, | ||
683 | getCellText: function(r,c) { | ||
684 | var p = this.photos[r]; | ||
685 | if(c.id=='sr_title') return p.title; | ||
686 | return c.id; | ||
687 | }, | ||
688 | setTree: function(t) { this.tree = t }, | ||
689 | isContainer: function(r) { return false }, | ||
690 | isSeparator: function(r) { return false }, | ||
691 | isSorted: function(r) { return false }, | ||
692 | getLevel: function(r) { return 0 }, | ||
693 | getImageSrc: function(r,c) { return null }, | ||
694 | getRowProperties: function(r,p) { }, | ||
695 | getCellProperties: function(cid,cel,p) { }, | ||
696 | getColumnProperties: function(cid,cel,p) { }, | ||
697 | cycleHeader: function(cid,e) { }, | ||
698 | getParentIndex: function(r) { return -1 }, | ||
699 | drop: function(r,o) { }, | ||
700 | canDropBeforeAfter: function(r,b) { return false }, | ||
701 | |||
702 | importXPR: function(xp) { | ||
703 | this.selection.clearSelection(); | ||
704 | this.selection.currentIndex = -1; | ||
705 | this.searchresult_props.hidden = true; | ||
706 | this.tree.beginUpdateBatch(); | ||
707 | this.photos = new Array(); | ||
708 | var n; while(n=xp.iterateNext()) { | ||
709 | this.photos.push(new Photo(n)); | ||
710 | } | ||
711 | this.rowCount = this.photos.length; | ||
712 | this.tree.endUpdateBatch(); | ||
713 | }, | ||
714 | search_photos: function() { | ||
715 | var pars = { | ||
716 | method: 'flickr.photos.search', | ||
717 | auth_token: 'default', | ||
718 | extras: 'license,date_upload,date_taken,owner_name,icon_server,original_format,last_update,geo' | ||
719 | }; | ||
720 | if(this.search_mine.checked) | ||
721 | pars.user_id='me'; | ||
722 | if(this.search_tags.checked) { | ||
723 | pars.tags=this.search_for.value.split(/ +/).join(','); | ||
724 | }else{ | ||
725 | pars.text=this.search_for.value; | ||
726 | } | ||
727 | var _this = this; | ||
728 | this.fireflix.flickr.api_call( pars, | ||
729 | function(xr) { | ||
730 | var x = xr.responseXML; | ||
731 | var xp = x.evaluate( | ||
732 | '/rsp/photos/photo', x, null, | ||
733 | XPathResult.ORDERED_NODE_ITERATOR_TYPE, null ); | ||
734 | _this.importXPR(xp); | ||
735 | _this.on_select(); | ||
736 | }, function(x,s,c,m) { | ||
737 | _this.fireflix.flickr_failure(x,s,c,m); | ||
738 | } | ||
739 | ); | ||
740 | }, | ||
741 | on_select: function() { | ||
742 | if(this.selection.currentIndex<0) { | ||
743 | this.searchresult_props.hidden = true; | ||
744 | }else{ | ||
745 | var p = this.photos[this.selection.currentIndex]; | ||
746 | if(!p) { | ||
747 | this.searchresult_props.hidden = true; | ||
748 | }else{ | ||
749 | this.search_photo.src = this.fireflix.flickr.make_photo_url(p,'t'); | ||
750 | this.searchresult_title.value = p.title; | ||
751 | this.searchresult_description.value = null; | ||
752 | if(p.description==null && p.description==undefined) { | ||
753 | var pid = p.id; | ||
754 | var ci = this.selection.currentIndex; | ||
755 | var _this = this; | ||
756 | this.fireflix.flickr.api_call( | ||
757 | { | ||
758 | method: 'flickr.photos.getInfo', | ||
759 | auth_token: 'default', | ||
760 | photo_id: p.id, | ||
761 | secret: p.secret | ||
762 | }, function(xr) { | ||
763 | var pp = _this.photos[ci]; | ||
764 | if(ci==_this.selection.currentIndex && pp.id==pid) { | ||
765 | var n = xp_node('/rsp/photo',xr.responseXML); | ||
766 | pp.fromNode_(n); | ||
767 | _this.searchresult_description.value=pp.description?pp.description:null; | ||
768 | } | ||
769 | }, function(x,s,c,m) { | ||
770 | _this.fireflix.flickr_failure(x,s,c,m); | ||
771 | } | ||
772 | ); | ||
773 | this.searchresult_props.hidden = false; | ||
774 | }else{ | ||
775 | this.searchresult_description.value=p.description?p.description:null; | ||
776 | } | ||
777 | } | ||
778 | } | ||
779 | }, | ||
780 | on_cmd_open: function(ev) { | ||
781 | if(this.selection.currentIndex<0) | ||
782 | return; | ||
783 | var p = this.photos[this.selection.currentIndex]; | ||
784 | if(!p.id) | ||
785 | return; | ||
786 | this.fireflix.openTab(this.fireflix.flickr.make_photo_url(p,'p')); | ||
787 | } | ||
788 | }, | ||
789 | |||
790 | photo_html: function(p,i,l) { | ||
791 | // TODO: add alt/title when possible | ||
792 | var rv = | ||
793 | '<a href="'+this.flickr.make_photo_url(p,l)+'">' + | ||
794 | '<img src="'+this.flickr.make_photo_url(p,i)+'" />'+ | ||
795 | '</a>'; | ||
796 | return rv; | ||
797 | }, | ||
798 | build_html: function(photos,uti,utl) { | ||
799 | var rv = ''; | ||
800 | for(var i in photos) { | ||
801 | var p = photos[i]; | ||
802 | rv += this.photo_html(p,utl,uti)+'\n'; | ||
803 | } | ||
804 | return rv; | ||
805 | }, | ||
806 | |||
807 | popup_content: function(s) { | ||
808 | window.openDialog( | ||
809 | "chrome://fireflix/content/generated-content.xul", | ||
810 | null, "dialog,chrome", this, s ); | ||
811 | }, | ||
812 | copy_to_clipboard: function(s) { | ||
813 | var ch = Components.classes["@mozilla.org/widget/clipboardhelper;1"] | ||
814 | .getService(Components.interfaces.nsIClipboardHelper); | ||
815 | ch.copyString(s); | ||
816 | }, | ||
817 | openTab: function(l) { | ||
818 | var wm = Components.classes['@mozilla.org/appshell/window-mediator;1'].getService( | ||
819 | Components.interfaces.nsIWindowMediator ); | ||
820 | var bw = wm.getMostRecentWindow('navigator:browser'); | ||
821 | var b = bw.getBrowser(); | ||
822 | var t = b.addTab(l); | ||
823 | b.selectedTab = t; | ||
824 | }, | ||
825 | |||
826 | build_menus: function() { | ||
827 | this.append_html_menu( | ||
828 | document.getElementById('sets_html_menu'), | ||
829 | 'stm_','m_bop','cmdset_sets','cmd_sets_html' | ||
830 | ); | ||
831 | this.append_html_menu( | ||
832 | document.getElementById('uploads_html_menu'), | ||
833 | 'stm_','m_bop','cmdset_uploads','cmd_uploads_html' | ||
834 | ); | ||
835 | return; | ||
836 | }, | ||
837 | append_html_menu: function(m,imgt,lnkt,csid,cpfx) { | ||
838 | var mp = m.appendChild(document.createElement('menupopup')); | ||
839 | var t; | ||
840 | t=mp.appendChild(document.createElement('menuitem')); | ||
841 | t.setAttribute('label',this.loc_strings.getString('menutitle_Images')); | ||
842 | t.setAttribute('class','menuhead');t.setAttribute('disabled','true'); | ||
843 | mp.appendChild(document.createElement('menuseparator')); | ||
844 | var cs = document.getElementById(csid); | ||
845 | for(var iti=0;iti<imgt.length;++iti) { | ||
846 | t = mp.appendChild(document.createElement('menu')); | ||
847 | t.setAttribute('label',this.loc_strings.getString('urltype_'+imgt.charAt(iti))); | ||
848 | var smp = t.appendChild(document.createElement('menupopup')); | ||
849 | t=smp.appendChild(document.createElement('menuitem')); | ||
850 | t.setAttribute('label',this.loc_strings.getString('menutitle_Links')); | ||
851 | t.setAttribute('class','menuhead');t.setAttribute('disabled','true'); | ||
852 | smp.appendChild(document.createElement('menuseparator')); | ||
853 | for(var lti=0;lti<lnkt.length;++lti) { | ||
854 | var csfx = imgt.charAt(iti)+lnkt.charAt(lti); | ||
855 | t=smp.appendChild(document.createElement('menuitem')); | ||
856 | t.setAttribute('label',this.loc_strings.getString('urltype_'+lnkt.charAt(lti))); | ||
857 | t.setAttribute('command',cpfx+'_'+csfx); | ||
858 | t=cs.appendChild(document.createElement('command')); | ||
859 | t.setAttribute('id',cpfx+'_'+csfx); | ||
860 | t.setAttribute('oncommand','fireflix.on_'+cpfx+"('"+csfx+"',event)"); | ||
861 | } | ||
862 | } | ||
863 | return mp; | ||
864 | }, | ||
865 | |||
866 | flickr_failure: function(x,s,c,m) { | ||
867 | if(c==98) { // Invalid auth token | ||
868 | this.flickr.reset_token(); | ||
869 | document.getElementById('auth_info').value = this.no_auth_info_label; | ||
870 | document.getElementById('auth_info').disabled = true; | ||
871 | document.getElementById('b_auth').hidden = false; | ||
872 | return; | ||
873 | } | ||
874 | // TODO: is that beauty | ||
875 | alert('flickr api call failed\n'+c+' '+m); | ||
876 | } | ||
877 | |||
878 | }; | ||
diff --git a/content/flickr.js b/content/flickr.js new file mode 100644 index 0000000..3554796 --- a/dev/null +++ b/content/flickr.js | |||
@@ -0,0 +1,403 @@ | |||
1 | /* | ||
2 | * Photoset | ||
3 | */ | ||
4 | |||
5 | function Photoset(s) { | ||
6 | if(s instanceof Photoset) { | ||
7 | for(var p in s) this[p]=s[p]; | ||
8 | }else | ||
9 | this.fromNode(s); | ||
10 | } | ||
11 | Photoset.prototype = { | ||
12 | id: null, | ||
13 | primary: null, | ||
14 | secret: null, | ||
15 | server: null, | ||
16 | photos: null, | ||
17 | title: null, | ||
18 | description: null, | ||
19 | fromNode: function(n) { | ||
20 | this.id = n.getAttribute('id'); | ||
21 | this.primary = n.getAttribute('primary'); | ||
22 | this.secret = n.getAttribute('secret'); | ||
23 | this.server = n.getAttribute('server'); | ||
24 | this.photos = n.getAttribute('photos'); | ||
25 | this.title = n.getElementsByTagName('title').item(0).firstChild.nodeValue; | ||
26 | this.description = n.getElementsByTagName('description').item(0).firstChild; | ||
27 | if(this.description) this.description = this.description.nodeValue; | ||
28 | } | ||
29 | }; | ||
30 | |||
31 | /* | ||
32 | * Photo | ||
33 | */ | ||
34 | function Photo(s) { | ||
35 | if(s instanceof Photo) { | ||
36 | for(var p in s) this[p]=s[p]; | ||
37 | }else | ||
38 | this.fromNode(s); | ||
39 | } | ||
40 | Photo.prototype = { | ||
41 | id: null, secret: null, | ||
42 | server: null, | ||
43 | title: null, | ||
44 | isprimary: null, | ||
45 | license: null, | ||
46 | dateupload: null, datetaken: null, datetakengranularity: null, | ||
47 | ownername: null, | ||
48 | iconserver: null, | ||
49 | originalformat: null, | ||
50 | lastupdate: null, | ||
51 | fromNode: function(n) { | ||
52 | this.id = n.getAttribute('id'); this.secret = n.getAttribute('secret'); | ||
53 | this.server = n.getAttribute('server'); | ||
54 | this.title = n.getAttribute('title'); | ||
55 | this.isprimary = n.getAttribute('isprimary'); | ||
56 | this.license = n.getAttribute('license'); | ||
57 | this.dateupload = n.getAttribute('dateupload'); | ||
58 | this.datetaken = n.getAttribute('datetaken'); this.datetakengranularity = n.getAttribute('datetakengranularity'); | ||
59 | this.ownername = n.getAttribute('ownername'); | ||
60 | this.iconserver = n.getAttribute('iconserver'); | ||
61 | this.originalformat = n.getAttribute('originalformat'); | ||
62 | this.lastupdate = n.getAttribute('lastupdate'); | ||
63 | }, | ||
64 | fromNode_: function(n) { | ||
65 | var t; | ||
66 | // TODO: @rotation @isfavorite | ||
67 | this.owner = {}; | ||
68 | t = n.getElementsByTagName('owner').item(0); | ||
69 | if(t) { | ||
70 | this.owner.nsid=t.getAttribute('nsid'); | ||
71 | this.owner.username=t.getAttribute('username'); | ||
72 | this.owner.realname=t.getAttribute('realname'); | ||
73 | this.owner.location=t.getAttribute.location; | ||
74 | } | ||
75 | t = n.getElementsByTagName('description').item(0); | ||
76 | if(t && t.firstChild) { | ||
77 | this.description = t.firstChild.nodeValue; | ||
78 | } | ||
79 | // TODO: visibility/@ispublic visibility/@isfriend visibility/@isfamily | ||
80 | // TODO: dates/@posted dates/@taken dates/@takengranularity dates/@lastupdate | ||
81 | // TODO: permissions/@permcomment permsiions/@permaddmeta | ||
82 | // TODO: editability/@canaddcomment editability/@canaddmeta | ||
83 | // TODO: comments | ||
84 | // TODO: notes/note/@id notes/note/@author notes/note/@authorname | ||
85 | // TODO: notes/note/@x notes/note/@y notes/note/@w notes/note/@h | ||
86 | // TODO: notes/note | ||
87 | // TODO: tags/tag/@id tags/tag/@author tags/tag/@raw tags/tag | ||
88 | // TODO: urls/url/@type urls/url | ||
89 | } | ||
90 | }; | ||
91 | |||
92 | function toutf8(ucode) { | ||
93 | var rv = ''; | ||
94 | for(var i=0;i<ucode.length;++i) { | ||
95 | var cc = ucode.charCodeAt(i); | ||
96 | if(cc<=0x7F) | ||
97 | rv += ucode.charAt(i); | ||
98 | else if(cc<=0x7ff) | ||
99 | rv += String.fromCharCode( | ||
100 | 0xc0|((cc>> 6)&0x1f), | ||
101 | 0x80|( cc &0x3f) ); | ||
102 | else if(cc<=0xffff) | ||
103 | rv += String.fromCharCode( | ||
104 | 0xe0|((cc>>12)&0x0f), | ||
105 | 0x80|((cc>> 6)&0x3f), | ||
106 | 0x80|( cc &0x3f) ); | ||
107 | else if(cc<=0x1fffff) | ||
108 | rv += String.fromCharCode( | ||
109 | 0xf0|((cc>>18)&0x07), | ||
110 | 0x80|((cc>>12)&0x3f), | ||
111 | 0x80|((cc>> 6)&0x3f), | ||
112 | 0x80|( cc &0x3f) ); | ||
113 | else if(cc<=0x03ffffff) | ||
114 | rv += String.fromCharCode( | ||
115 | 0xf8|((cc>>24)&0x03), | ||
116 | 0x80|((cc>>18)&0x3f), | ||
117 | 0x80|((cc>>12)&0x3f), | ||
118 | 0x80|((cc>> 6)&0x3f), | ||
119 | 0x80|( cc &0x3f) ); | ||
120 | else if(cc<=0x7fffffff) | ||
121 | rv += String.fromCharCode( | ||
122 | 0xfc|((cc>>30)&0x01), | ||
123 | 0x80|((cc>>24)&0x3f), | ||
124 | 0x80|((cc>>18)&0x3f), | ||
125 | 0x80|((cc>>12)&0x3f), | ||
126 | 0x80|((cc>> 6)&0x3f), | ||
127 | 0x80|( cc &0x3f) ); | ||
128 | } | ||
129 | return rv; | ||
130 | } | ||
131 | function xp_str(xp,x) { | ||
132 | var rv = x.evaluate( | ||
133 | xp, x, null, XPathResult.STRING_TYPE, null ); | ||
134 | return rv.stringValue; | ||
135 | } | ||
136 | function xp_node(xp,x) { | ||
137 | var rv = x.evaluate( | ||
138 | xp, x, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null ); | ||
139 | return rv.singleNodeValue; | ||
140 | } | ||
141 | |||
142 | function Flickr() { } | ||
143 | Flickr.prototype = { | ||
144 | |||
145 | rest_url: 'http://www.flickr.com/services/rest/', | ||
146 | auth_url: 'http://flickr.com/services/auth/', | ||
147 | photo_url: 'http://static.flickr.com/', | ||
148 | photos_url: 'http://www.flickr.com/photos/', | ||
149 | upload_url: 'http://www.flickr.com/services/upload/', | ||
150 | |||
151 | api_sig: function(paramstr) { | ||
152 | return MD5(toutf8(this.api_shs+paramstr)); | ||
153 | }, | ||
154 | api_call_url: function(params,url) { | ||
155 | params.api_key = this.api_key; | ||
156 | var pp = new Array(); | ||
157 | for(var p in params) { | ||
158 | pp.push(p); | ||
159 | } | ||
160 | var pstr = ''; | ||
161 | var rv = (url?url:this.rest_url)+'?'; | ||
162 | for(var p in pp.sort()) { | ||
163 | var pn = pp[p]; | ||
164 | pstr += pn+params[pn]; | ||
165 | rv += pn+'='+params[pn]+'&'; | ||
166 | } | ||
167 | rv += 'api_sig='+this.api_sig(pstr); | ||
168 | return rv; | ||
169 | }, | ||
170 | api_call: function(params, on_success, on_failure) { | ||
171 | if(params.auth_token == 'default') | ||
172 | params.auth_token = this.token; | ||
173 | var x = new XMLHttpRequest(); | ||
174 | x.open("GET",this.api_call_url(params)); | ||
175 | x.onreadystatechange=function() { | ||
176 | if(x.readyState!=4) return false; | ||
177 | if(x.status==200) { | ||
178 | var stat = x.responseXML.firstChild.getAttribute('stat'); | ||
179 | if(stat=='ok') { | ||
180 | if(on_success) on_success(x); | ||
181 | }else{ | ||
182 | var e = x.responseXML.getElementsByTagName('err').item(0); | ||
183 | var ecode = e.getAttribute('code'); | ||
184 | var emsg = e.getAttribute('msg'); | ||
185 | dump(params.method+' failed: '+ecode+' '+emsg+'\n'); | ||
186 | if(on_failure) on_failure(x,stat,ecode,emsg); | ||
187 | } | ||
188 | }else{ | ||
189 | if(on_failure) on_failure(x); | ||
190 | } | ||
191 | return true; | ||
192 | } | ||
193 | x.send(null); | ||
194 | return true; | ||
195 | }, | ||
196 | |||
197 | frob: null, | ||
198 | authorize_0: function(on_s, on_f) { | ||
199 | var _this = this; | ||
200 | this.api_call( | ||
201 | { method: 'flickr.auth.getFrob' }, | ||
202 | function(x) { | ||
203 | _this.frob = xp_str('/rsp/frob',x.responseXML); | ||
204 | var u = _this.api_call_url( | ||
205 | { frob: _this.frob, perms: 'delete' }, _this.auth_url ); | ||
206 | var wm = Components.classes['@mozilla.org/appshell/window-mediator;1'].getService( | ||
207 | Components.interfaces.nsIWindowMediator ); | ||
208 | var bw = wm.getMostRecentWindow('navigator:browser'); | ||
209 | var b = bw.getBrowser(); | ||
210 | var t = b.addTab(u); | ||
211 | b.selectedTab = t; | ||
212 | if(on_s) on_s(); | ||
213 | }, function(x,s,c,m) { | ||
214 | if(on_f) on_f(x,s,c,m); | ||
215 | } | ||
216 | ); | ||
217 | }, | ||
218 | token: null, | ||
219 | perms: null, | ||
220 | user: null, | ||
221 | authorize_1: function(on_s, on_f) { | ||
222 | var _this = this; | ||
223 | this.api_call( | ||
224 | { method: 'flickr.auth.getToken', frob: this.frob }, | ||
225 | function(x) { | ||
226 | _this.token = xp_str('/rsp/auth/token',x.responseXML); | ||
227 | _this.perms = xp_str('/rsp/auth/perms',x.responseXML); | ||
228 | var u = xp_node('/rsp/auth/user',x.responseXML); | ||
229 | _this.user = { | ||
230 | nsid: u.getAttribute('nsid'), | ||
231 | username: u.getAttribute('username'), | ||
232 | fullname: u.getAttribute('fullname') | ||
233 | }; | ||
234 | if(on_s) on_s(x); | ||
235 | }, function(x,s,c,m) { | ||
236 | if(on_f) on_f(x,s,c,m); | ||
237 | } | ||
238 | ); | ||
239 | }, | ||
240 | |||
241 | prefs: Components.classes['@mozilla.org/preferences-service;1'].getService( | ||
242 | Components.interfaces.nsIPrefBranch | ||
243 | ), | ||
244 | prefs_root: 'net.klever.kin.flickr', | ||
245 | save_token: function() { | ||
246 | // TODO: don't clear when there's nothing to clear or catch exceptions | ||
247 | if(this.token) | ||
248 | this.prefs.setCharPref(this.prefs_root+'.auth_token',this.token); | ||
249 | else | ||
250 | this.prefs.clearUserPref(this.prefs_root+'.auth_token'); | ||
251 | if(this.perms) | ||
252 | this.prefs.setCharPref(this.prefs_root+'.auth_perms',this.perms); | ||
253 | else | ||
254 | this.prefs.clearUserPref(this.prefs_root+'.auth_perms'); | ||
255 | if(this.user && this.user.nsid!=null && this.user.nsid!=undefined) | ||
256 | this.prefs.setCharPref(this.prefs_root+'.auth_user.nsid',this.user.nsid); | ||
257 | else | ||
258 | this.prefs.clearUserPref(this.prefs_root+'.auth_user.nsid'); | ||
259 | if(this.user && this.user.username!=null && this.user.username!=undefined) | ||
260 | this.prefs.setCharPref(this.prefs_root+'.auth_user.username',this.user.username); | ||
261 | else | ||
262 | this.prefs.clearUserPref(this.prefs_root+'.auth_user.username'); | ||
263 | if(this.user && this.user.fullname!=null && this.user.fullname!=undefined) | ||
264 | this.prefs.setCharPref(this.prefs_root+'.auth_user.fullname',this.user.fullname); | ||
265 | else | ||
266 | this.prefs.clearUserPref(this.prefs_root+'.auth_user.fullname'); | ||
267 | }, | ||
268 | _reset_token: function() { | ||
269 | this.token = null; this.perms = null; this.user = null; | ||
270 | return false; | ||
271 | }, | ||
272 | load_token: function() { | ||
273 | try { | ||
274 | if(this.prefs.getPrefType(this.prefs_root+'.auth_token')!=this.prefs.PREF_STRING) | ||
275 | return this._reset_token(); | ||
276 | this.token = this.prefs.getCharPref(this.prefs_root+'.auth_token'); | ||
277 | if(this.prefs.getPrefType(this.prefs_root+'.auth_perms')!=this.prefs.PREF_STRING) | ||
278 | return this._reset_token(); | ||
279 | this.perms = this.prefs.getCharPref(this.prefs_root+'.auth_perms'); | ||
280 | if(this.prefs.getPrefType(this.prefs_root+'.auth_user.nsid')!=this.prefs.PREF_STRING) | ||
281 | return this._reset_token(); | ||
282 | this.user = new Object(); | ||
283 | this.user.nsid = this.prefs.getCharPref(this.prefs_root+'.auth_user.nsid'); | ||
284 | if(this.prefs.getPrefType(this.prefs_root+'.auth_user.username')!=this.prefs.PREF_STRING) | ||
285 | return this._reset_token(); | ||
286 | this.user.username = this.prefs.getCharPref(this.prefs_root+'.auth_user.username'); | ||
287 | if(this.prefs.getPrefType(this.prefs_root+'.auth_user.fullname')!=this.prefs.PREF_STRING) | ||
288 | return this._reset_token(); | ||
289 | this.user.fullname = this.prefs.getCharPref(this.prefs_root+'.auth_user.fullname'); | ||
290 | }catch(e) { return this._reset_token(); } | ||
291 | return true; | ||
292 | }, | ||
293 | reset_token: function() { | ||
294 | this._reset_token(); | ||
295 | this.save_token(); | ||
296 | }, | ||
297 | |||
298 | get_photo_url: function(ser,id,sec,sfx,ext) { | ||
299 | var rv = this.photo_url + ser + '/' + id + '_' + sec; | ||
300 | if(sfx && sfx!='_') rv += '_'+sfx; | ||
301 | rv += ext?'.'+ext:'.jpg'; | ||
302 | return rv; | ||
303 | }, | ||
304 | get_image_url: function(o,sfx) { | ||
305 | return this.get_photo_url( | ||
306 | o.server, | ||
307 | (o instanceof Photoset)? o.primary : o.id, | ||
308 | o.secret, | ||
309 | sfx, | ||
310 | (sfx=='o')?o.originalformat:null | ||
311 | ); | ||
312 | }, | ||
313 | get_photo_page_url: function(p) { | ||
314 | if(p instanceof Photo) // TODO: half wrong, what if no owner? | ||
315 | return this.photos_url + (p.owner.nsid?p.owner.nsid:this.user.nsid) + '/' + p.id; | ||
316 | else // TODO: take owner into account? | ||
317 | return this.photos_url + this.user.nsid + '/' + p; | ||
318 | }, | ||
319 | make_photo_url: function(p,sfx) { | ||
320 | if(sfx=='p') | ||
321 | return this.get_photo_page_url(p); | ||
322 | else | ||
323 | return this.get_image_url(p,sfx); | ||
324 | }, | ||
325 | |||
326 | upload_file: function(f,fa,on_success,on_failure) { | ||
327 | try { | ||
328 | var fi = Components.classes["@mozilla.org/file/local;1"] | ||
329 | .createInstance(Components.interfaces.nsILocalFile); | ||
330 | fi.initWithPath( f ); | ||
331 | var st = Components.classes["@mozilla.org/network/file-input-stream;1"] | ||
332 | .createInstance(Components.interfaces.nsIFileInputStream); | ||
333 | st.init(fi,0x01,00004,null); | ||
334 | var bis = Components.classes["@mozilla.org/binaryinputstream;1"] | ||
335 | .createInstance(Components.interfaces.nsIBinaryInputStream); | ||
336 | bis.setInputStream(st); | ||
337 | |||
338 | // allocate and initialize temp storage string | ||
339 | var pbs = Components.classes["@mozilla.org/storagestream;1"] | ||
340 | .createInstance(Components.interfaces.nsIStorageStream); | ||
341 | pbs.init(1024,10000000,null); | ||
342 | // create output stream | ||
343 | var pbos = pbs.getOutputStream(0); | ||
344 | // and a binaryoutputstream interface | ||
345 | var pbbos = Components.classes["@mozilla.org/binaryoutputstream;1"] | ||
346 | .createInstance(Components.interfaces.nsIBinaryOutputStream); | ||
347 | pbbos.setOutputStream(pbos); | ||
348 | |||
349 | /* create POST body */ | ||
350 | var boundarytoken = 'kadaroloongazaduviaxamma'; | ||
351 | var boundary = '--'+boundarytoken; | ||
352 | var b = ''; | ||
353 | |||
354 | var parms = { api_key: this.api_key, auth_token: this.token }; | ||
355 | for(var p in fa) parms[p] = fa[p]; | ||
356 | var pns = new Array(); | ||
357 | for(var p in parms) pns.push(p); | ||
358 | var pstr = ''; | ||
359 | for(var p in pns.sort()) { | ||
360 | var pn = pns[p]; | ||
361 | pstr += pn+parms[pn]; | ||
362 | b += boundary+'\nContent-Disposition: form-data; name="'+pn+'"\n\n'+toutf8(parms[pn])+'\n'; | ||
363 | } | ||
364 | b += boundary+'\nContent-Disposition: form-data; name="api_sig"\n\n'+this.api_sig(pstr)+'\n'; | ||
365 | b += boundary+'\nContent-Disposition: form-data; name="photo"; filename="'+f+'"\nContent-Type: image/jpeg\nContent-Transfer-Encoding: binary\n\n'; | ||
366 | pbbos.writeBytes(b,b.length); | ||
367 | var bisbytes = bis.available(); | ||
368 | pbbos.writeBytes(bis.readBytes(bisbytes),bisbytes); | ||
369 | pbbos.writeBytes('\n'+boundary+'--',3+boundary.length); bis.close(); st.close(); | ||
370 | |||
371 | pbbos.close(); pbos.close(); | ||
372 | |||
373 | var x = new XMLHttpRequest(); | ||
374 | x.open("POST",this.upload_url); | ||
375 | x.setRequestHeader('Content-Type', 'multipart/form-data; boundary="'+boundarytoken+'"'); | ||
376 | x.setRequestHeader('Connection','close'); | ||
377 | x.setRequestHeader('Content-Length',b.length); | ||
378 | x.onreadystatechange=function() { | ||
379 | if(x.readyState!=4) return false; | ||
380 | if(x.status==200) { | ||
381 | var stat = x.responseXML.firstChild.getAttribute('stat'); | ||
382 | if(stat=='ok') { | ||
383 | var pid = xp_str('/rsp/photoid',x.responseXML); | ||
384 | if(on_success) on_success(x,pid); | ||
385 | }else{ | ||
386 | var e = x.responseXML.getElementsByTagName('err').item(0); | ||
387 | var ecode = e.getAttribute('code'); | ||
388 | var emsg = e.getAttribute('msg'); | ||
389 | dump('upload failed: '+ecode+' '+emsg+'\n'); | ||
390 | if(on_failure) on_failure(x,stat,ecode,emsg); | ||
391 | } | ||
392 | }else{ | ||
393 | if(on_failure) on_failure(x); | ||
394 | } | ||
395 | return true; | ||
396 | }; | ||
397 | x.send(pbs.newInputStream(0)); | ||
398 | }catch(e) { | ||
399 | if(on_failure) on_failure(e,null,-1,e.message); | ||
400 | } | ||
401 | } | ||
402 | |||
403 | }; | ||
diff --git a/content/generated-content.js b/content/generated-content.js new file mode 100644 index 0000000..0ad08bb --- a/dev/null +++ b/content/generated-content.js | |||
@@ -0,0 +1,17 @@ | |||
1 | var generated = { | ||
2 | fireflix: null, | ||
3 | data: null, | ||
4 | |||
5 | init: function() { | ||
6 | this.fireflix = window.arguments[0]; | ||
7 | this.data = window.arguments[1]; | ||
8 | this.databox = document.getElementById('data'); | ||
9 | this.databox.value = this.data; | ||
10 | this.databox.select(); | ||
11 | }, | ||
12 | copy: function() { | ||
13 | var ch = Components.classes["@mozilla.org/widget/clipboardhelper;1"] | ||
14 | .getService(Components.interfaces.nsIClipboardHelper); | ||
15 | ch.copyString(this.data); | ||
16 | } | ||
17 | }; | ||
diff --git a/content/generated-content.xul b/content/generated-content.xul new file mode 100644 index 0000000..2a91efa --- a/dev/null +++ b/content/generated-content.xul | |||
@@ -0,0 +1,20 @@ | |||
1 | <?xml version="1.0" encoding="utf-8"?> | ||
2 | <?xml-stylesheet href="chrome://global/skin/" type="text/css"?> | ||
3 | <?xsml-stylesheet href="fireflix.css" type="text/css"?> | ||
4 | <!DOCTYPE dialog SYSTEM "chrome://fireflix/locale/fireflix.dtd"> | ||
5 | <dialog | ||
6 | xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" | ||
7 | id="generated_content" | ||
8 | buttons="accept" | ||
9 | defaultbutton="accept" | ||
10 | title="&generated.title;" | ||
11 | onload="generated.init()" | ||
12 | > | ||
13 | |||
14 | <script src="generated-content.js" type="application/x-javascript"/> | ||
15 | |||
16 | <vbox class="generated wholething" flex="1"> | ||
17 | <textbox flex="1" minheight="300" minwidth="300" id="data" multiline="true" readonly="true" /> | ||
18 | <button id="copy" label="&generated.copy;" oncommand="generated.copy()" /> | ||
19 | </vbox> | ||
20 | </dialog> | ||
diff --git a/content/icons/16x16/fireflix.png b/content/icons/16x16/fireflix.png new file mode 100644 index 0000000..377ab28 --- a/dev/null +++ b/content/icons/16x16/fireflix.png | |||
Binary files differ | |||
diff --git a/content/icons/32x32/fireflix.png b/content/icons/32x32/fireflix.png new file mode 100644 index 0000000..374ebbd --- a/dev/null +++ b/content/icons/32x32/fireflix.png | |||
Binary files differ | |||
diff --git a/content/md5.js b/content/md5.js new file mode 100644 index 0000000..f22db2b --- a/dev/null +++ b/content/md5.js | |||
@@ -0,0 +1,154 @@ | |||
1 | /* MD5 Message-Digest Algorithm - JavaScript | ||
2 | ' MODIFICATION HISTORY: | ||
3 | ' 1.0 16-Feb-2001 - Phil Fresle (sales@frez.co.uk) - Initial Version (VB/ASP code) | ||
4 | ' 1.0 21-Feb-2001 - Enrico Mosanghini (erik504@yahoo.com) - JavaScript porting | ||
5 | */ | ||
6 | function MD5(sMessage) { | ||
7 | function RotateLeft(lValue, iShiftBits) { return (lValue<<iShiftBits) | (lValue>>>(32-iShiftBits)); } | ||
8 | function AddUnsigned(lX,lY) { | ||
9 | var lX4,lY4,lX8,lY8,lResult; | ||
10 | lX8 = (lX & 0x80000000); | ||
11 | lY8 = (lY & 0x80000000); | ||
12 | lX4 = (lX & 0x40000000); | ||
13 | lY4 = (lY & 0x40000000); | ||
14 | lResult = (lX & 0x3FFFFFFF)+(lY & 0x3FFFFFFF); | ||
15 | if (lX4 & lY4) return (lResult ^ 0x80000000 ^ lX8 ^ lY8); | ||
16 | if (lX4 | lY4) { | ||
17 | if (lResult & 0x40000000) return (lResult ^ 0xC0000000 ^ lX8 ^ lY8); | ||
18 | else return (lResult ^ 0x40000000 ^ lX8 ^ lY8); | ||
19 | } else return (lResult ^ lX8 ^ lY8); | ||
20 | } | ||
21 | function F(x,y,z) { return (x & y) | ((~x) & z); } | ||
22 | function G(x,y,z) { return (x & z) | (y & (~z)); } | ||
23 | function H(x,y,z) { return (x ^ y ^ z); } | ||
24 | function I(x,y,z) { return (y ^ (x | (~z))); } | ||
25 | function FF(a,b,c,d,x,s,ac) { | ||
26 | a = AddUnsigned(a, AddUnsigned(AddUnsigned(F(b, c, d), x), ac)); | ||
27 | return AddUnsigned(RotateLeft(a, s), b); | ||
28 | } | ||
29 | function GG(a,b,c,d,x,s,ac) { | ||
30 | a = AddUnsigned(a, AddUnsigned(AddUnsigned(G(b, c, d), x), ac)); | ||
31 | return AddUnsigned(RotateLeft(a, s), b); | ||
32 | } | ||
33 | function HH(a,b,c,d,x,s,ac) { | ||
34 | a = AddUnsigned(a, AddUnsigned(AddUnsigned(H(b, c, d), x), ac)); | ||
35 | return AddUnsigned(RotateLeft(a, s), b); | ||
36 | } | ||
37 | function II(a,b,c,d,x,s,ac) { | ||
38 | a = AddUnsigned(a, AddUnsigned(AddUnsigned(I(b, c, d), x), ac)); | ||
39 | return AddUnsigned(RotateLeft(a, s), b); | ||
40 | } | ||
41 | function ConvertToWordArray(sMessage) { | ||
42 | var lWordCount; | ||
43 | var lMessageLength = sMessage.length; | ||
44 | var lNumberOfWords_temp1=lMessageLength + 8; | ||
45 | var lNumberOfWords_temp2=(lNumberOfWords_temp1-(lNumberOfWords_temp1 % 64))/64; | ||
46 | var lNumberOfWords = (lNumberOfWords_temp2+1)*16; | ||
47 | var lWordArray=Array(lNumberOfWords-1); | ||
48 | var lBytePosition = 0; | ||
49 | var lByteCount = 0; | ||
50 | while ( lByteCount < lMessageLength ) { | ||
51 | lWordCount = (lByteCount-(lByteCount % 4))/4; | ||
52 | lBytePosition = (lByteCount % 4)*8; | ||
53 | lWordArray[lWordCount] = (lWordArray[lWordCount] | (sMessage.charCodeAt(lByteCount)<<lBytePosition)); | ||
54 | lByteCount++; | ||
55 | } | ||
56 | lWordCount = (lByteCount-(lByteCount % 4))/4; | ||
57 | lBytePosition = (lByteCount % 4)*8; | ||
58 | lWordArray[lWordCount] = lWordArray[lWordCount] | (0x80<<lBytePosition); | ||
59 | lWordArray[lNumberOfWords-2] = lMessageLength<<3; | ||
60 | lWordArray[lNumberOfWords-1] = lMessageLength>>>29; | ||
61 | return lWordArray; | ||
62 | } | ||
63 | function WordToHex(lValue) { | ||
64 | var WordToHexValue="",WordToHexValue_temp="",lByte,lCount; | ||
65 | for (lCount = 0;lCount<=3;lCount++) { | ||
66 | lByte = (lValue>>>(lCount*8)) & 255; | ||
67 | WordToHexValue_temp = "0" + lByte.toString(16); | ||
68 | WordToHexValue = WordToHexValue + WordToHexValue_temp.substr(WordToHexValue_temp.length-2,2); | ||
69 | } | ||
70 | return WordToHexValue; | ||
71 | } | ||
72 | var x=Array(); | ||
73 | var k,AA,BB,CC,DD,a,b,c,d | ||
74 | var S11=7, S12=12, S13=17, S14=22; | ||
75 | var S21=5, S22=9 , S23=14, S24=20; | ||
76 | var S31=4, S32=11, S33=16, S34=23; | ||
77 | var S41=6, S42=10, S43=15, S44=21; | ||
78 | // Steps 1 and 2. Append padding bits and length and convert to words | ||
79 | x = ConvertToWordArray(sMessage); | ||
80 | // Step 3. Initialise | ||
81 | a = 0x67452301; b = 0xEFCDAB89; c = 0x98BADCFE; d = 0x10325476; | ||
82 | // Step 4. Process the message in 16-word blocks | ||
83 | for (k=0;k<x.length;k+=16) { | ||
84 | AA=a; BB=b; CC=c; DD=d; | ||
85 | a=FF(a,b,c,d,x[k+0], S11,0xD76AA478); | ||
86 | d=FF(d,a,b,c,x[k+1], S12,0xE8C7B756); | ||
87 | c=FF(c,d,a,b,x[k+2], S13,0x242070DB); | ||
88 | b=FF(b,c,d,a,x[k+3], S14,0xC1BDCEEE); | ||
89 | a=FF(a,b,c,d,x[k+4], S11,0xF57C0FAF); | ||
90 | d=FF(d,a,b,c,x[k+5], S12,0x4787C62A); | ||
91 | c=FF(c,d,a,b,x[k+6], S13,0xA8304613); | ||
92 | b=FF(b,c,d,a,x[k+7], S14,0xFD469501); | ||
93 | a=FF(a,b,c,d,x[k+8], S11,0x698098D8); | ||
94 | d=FF(d,a,b,c,x[k+9], S12,0x8B44F7AF); | ||
95 | c=FF(c,d,a,b,x[k+10],S13,0xFFFF5BB1); | ||
96 | b=FF(b,c,d,a,x[k+11],S14,0x895CD7BE); | ||
97 | a=FF(a,b,c,d,x[k+12],S11,0x6B901122); | ||
98 | d=FF(d,a,b,c,x[k+13],S12,0xFD987193); | ||
99 | c=FF(c,d,a,b,x[k+14],S13,0xA679438E); | ||
100 | b=FF(b,c,d,a,x[k+15],S14,0x49B40821); | ||
101 | a=GG(a,b,c,d,x[k+1], S21,0xF61E2562); | ||
102 | d=GG(d,a,b,c,x[k+6], S22,0xC040B340); | ||
103 | c=GG(c,d,a,b,x[k+11],S23,0x265E5A51); | ||
104 | b=GG(b,c,d,a,x[k+0], S24,0xE9B6C7AA); | ||
105 | a=GG(a,b,c,d,x[k+5], S21,0xD62F105D); | ||
106 | d=GG(d,a,b,c,x[k+10],S22,0x2441453); | ||
107 | c=GG(c,d,a,b,x[k+15],S23,0xD8A1E681); | ||
108 | b=GG(b,c,d,a,x[k+4], S24,0xE7D3FBC8); | ||
109 | a=GG(a,b,c,d,x[k+9], S21,0x21E1CDE6); | ||
110 | d=GG(d,a,b,c,x[k+14],S22,0xC33707D6); | ||
111 | c=GG(c,d,a,b,x[k+3], S23,0xF4D50D87); | ||
112 | b=GG(b,c,d,a,x[k+8], S24,0x455A14ED); | ||
113 | a=GG(a,b,c,d,x[k+13],S21,0xA9E3E905); | ||
114 | d=GG(d,a,b,c,x[k+2], S22,0xFCEFA3F8); | ||
115 | c=GG(c,d,a,b,x[k+7], S23,0x676F02D9); | ||
116 | b=GG(b,c,d,a,x[k+12],S24,0x8D2A4C8A); | ||
117 | a=HH(a,b,c,d,x[k+5], S31,0xFFFA3942); | ||
118 | d=HH(d,a,b,c,x[k+8], S32,0x8771F681); | ||
119 | c=HH(c,d,a,b,x[k+11],S33,0x6D9D6122); | ||
120 | b=HH(b,c,d,a,x[k+14],S34,0xFDE5380C); | ||
121 | a=HH(a,b,c,d,x[k+1], S31,0xA4BEEA44); | ||
122 | d=HH(d,a,b,c,x[k+4], S32,0x4BDECFA9); | ||
123 | c=HH(c,d,a,b,x[k+7], S33,0xF6BB4B60); | ||
124 | b=HH(b,c,d,a,x[k+10],S34,0xBEBFBC70); | ||
125 | a=HH(a,b,c,d,x[k+13],S31,0x289B7EC6); | ||
126 | d=HH(d,a,b,c,x[k+0], S32,0xEAA127FA); | ||
127 | c=HH(c,d,a,b,x[k+3], S33,0xD4EF3085); | ||
128 | b=HH(b,c,d,a,x[k+6], S34,0x4881D05); | ||
129 | a=HH(a,b,c,d,x[k+9], S31,0xD9D4D039); | ||
130 | d=HH(d,a,b,c,x[k+12],S32,0xE6DB99E5); | ||
131 | c=HH(c,d,a,b,x[k+15],S33,0x1FA27CF8); | ||
132 | b=HH(b,c,d,a,x[k+2], S34,0xC4AC5665); | ||
133 | a=II(a,b,c,d,x[k+0], S41,0xF4292244); | ||
134 | d=II(d,a,b,c,x[k+7], S42,0x432AFF97); | ||
135 | c=II(c,d,a,b,x[k+14],S43,0xAB9423A7); | ||
136 | b=II(b,c,d,a,x[k+5], S44,0xFC93A039); | ||
137 | a=II(a,b,c,d,x[k+12],S41,0x655B59C3); | ||
138 | d=II(d,a,b,c,x[k+3], S42,0x8F0CCC92); | ||
139 | c=II(c,d,a,b,x[k+10],S43,0xFFEFF47D); | ||
140 | b=II(b,c,d,a,x[k+1], S44,0x85845DD1); | ||
141 | a=II(a,b,c,d,x[k+8], S41,0x6FA87E4F); | ||
142 | d=II(d,a,b,c,x[k+15],S42,0xFE2CE6E0); | ||
143 | c=II(c,d,a,b,x[k+6], S43,0xA3014314); | ||
144 | b=II(b,c,d,a,x[k+13],S44,0x4E0811A1); | ||
145 | a=II(a,b,c,d,x[k+4], S41,0xF7537E82); | ||
146 | d=II(d,a,b,c,x[k+11],S42,0xBD3AF235); | ||
147 | c=II(c,d,a,b,x[k+2], S43,0x2AD7D2BB); | ||
148 | b=II(b,c,d,a,x[k+9], S44,0xEB86D391); | ||
149 | a=AddUnsigned(a,AA); b=AddUnsigned(b,BB); c=AddUnsigned(c,CC); d=AddUnsigned(d,DD); | ||
150 | } | ||
151 | // Step 5. Output the 128 bit digest | ||
152 | var temp= WordToHex(a)+WordToHex(b)+WordToHex(c)+WordToHex(d); | ||
153 | return temp.toLowerCase(); | ||
154 | } | ||
diff --git a/content/photoset-props.js b/content/photoset-props.js new file mode 100644 index 0000000..43dc1b9 --- a/dev/null +++ b/content/photoset-props.js | |||
@@ -0,0 +1,81 @@ | |||
1 | |||
2 | var psetprops = { | ||
3 | fireflix: null, | ||
4 | photoset: null, | ||
5 | pripic: null, | ||
6 | |||
7 | settitle: null, setdesc: null, | ||
8 | primarypic: null, | ||
9 | photos: new Array(), | ||
10 | init: function() { | ||
11 | this.fireflix = window.arguments[0]; | ||
12 | this.photoset = window.arguments[1]; | ||
13 | this.settitle = document.getElementById('set_title'); | ||
14 | this.settitle.value = this.photoset.title; | ||
15 | this.setdesc = document.getElementById('set_desc'); | ||
16 | this.setdesc.value = this.photoset.description; | ||
17 | this.primarypic = document.getElementById('primary_picture'); | ||
18 | this.primarypic.src = | ||
19 | this.fireflix.flickr.get_image_url( this.photoset, 't' ); | ||
20 | this.primarypic.hidden = false; | ||
21 | this.picslist = document.getElementById('primary_picture_list'); | ||
22 | |||
23 | var _this = this; | ||
24 | this.fireflix.flickr.api_call( | ||
25 | { | ||
26 | method: 'flickr.photosets.getPhotos', | ||
27 | auth_token: 'default', | ||
28 | photoset_id: this.photoset.id | ||
29 | }, function(xr) { | ||
30 | var x = xr.responseXML; | ||
31 | var xp = x.evaluate( | ||
32 | '/rsp/photoset/photo', x, null, | ||
33 | XPathResult.ORDERED_NODE_ITERATOR_TYPE, null ); | ||
34 | _this.picslist.removeAllItems(); _this.photos= new Array(); | ||
35 | var n; while(n=xp.iterateNext()) { | ||
36 | _this.photos.push( | ||
37 | { | ||
38 | id: n.getAttribute('id'), | ||
39 | secret: n.getAttribute('secret'), | ||
40 | server: n.getAttribute('server') | ||
41 | } | ||
42 | ); | ||
43 | var ni = _this.picslist.appendItem( | ||
44 | n.getAttribute('title'), _this.photos.length-1 | ||
45 | ); | ||
46 | ni.setAttribute('command','cmd_select_picture'); | ||
47 | if(n.getAttribute('isprimary')==1) { | ||
48 | _this.picslist.selectedItem = ni; | ||
49 | _this.pripic = _this.photos[_this.photos.length-1]; | ||
50 | } | ||
51 | } | ||
52 | _this.picslist.hidden = false; | ||
53 | }, function() { } | ||
54 | ); | ||
55 | }, | ||
56 | on_select_picture: function(ev) { | ||
57 | var epic = ev.explicitOriginalTarget; | ||
58 | this.picslist.selectedItem = epic; | ||
59 | var pic = this.photos[this.picslist.selectedItem.value]; | ||
60 | this.pripic = pic; | ||
61 | this.primarypic.src = | ||
62 | this.fireflix.flickr.get_photo_url( | ||
63 | pic.server, | ||
64 | pic.id, | ||
65 | pic.secret, | ||
66 | 't' | ||
67 | ); | ||
68 | }, | ||
69 | on_accept: function() { | ||
70 | this.photoset.title = | ||
71 | document.getElementById('set_title').value; | ||
72 | this.photoset.description = | ||
73 | document.getElementById('set_desc').value; | ||
74 | this.photoset.server = this.pripic.server; | ||
75 | this.photoset.primary = this.pripic.id; | ||
76 | this.photoset.secret = this.pripic.secret; | ||
77 | this.photoset.dirty = true; | ||
78 | return; | ||
79 | } | ||
80 | }; | ||
81 | |||
diff --git a/content/photoset-props.xul b/content/photoset-props.xul new file mode 100644 index 0000000..e8f6d13 --- a/dev/null +++ b/content/photoset-props.xul | |||
@@ -0,0 +1,38 @@ | |||
1 | <?xml version="1.0" encoding="utf-8"?> | ||
2 | <?xml-stylesheet href="chrome://global/skin/" type="text/css"?> | ||
3 | <?xsml-stylesheet href="fireflix.css" type="text/css"?> | ||
4 | <!DOCTYPE dialog SYSTEM "chrome://fireflix/locale/fireflix.dtd"> | ||
5 | <dialog | ||
6 | xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" | ||
7 | id="photoset_props" | ||
8 | buttons="accept,cancel" | ||
9 | defaultbutton="accept" | ||
10 | title="&photosetprops.title;" | ||
11 | onload="psetprops.init()" | ||
12 | ondialogaccept="psetprops.on_accept()" | ||
13 | > | ||
14 | |||
15 | <script src="photoset-props.js" type="application/x-javascript"/> | ||
16 | |||
17 | <commandset> | ||
18 | <command id="cmd_select_picture" | ||
19 | oncommand="psetprops.on_select_picture(event)"/> | ||
20 | </commandset> | ||
21 | |||
22 | <hbox class="wholething"> | ||
23 | <vbox> | ||
24 | <menulist id="primary_picture_list" hidden="true" sizetopopup="always"/> | ||
25 | <hbox pack="center"> | ||
26 | <box width="100" pack="center"> | ||
27 | <image id="primary_picture" hidden="true"/> | ||
28 | </box> | ||
29 | </hbox> | ||
30 | </vbox> | ||
31 | <vbox flex="1" minwidth="300"> | ||
32 | <label control="set_title" value="&photosetprops.set_title.label;"/> | ||
33 | <textbox id="set_title" /> | ||
34 | <label control="set_desc" value="&photosetprops.set_desc.label;"/> | ||
35 | <textbox id="set_desc" multiline="true" rows="5" /> | ||
36 | </vbox> | ||
37 | </hbox> | ||
38 | </dialog> | ||
diff --git a/install.rdf.in b/install.rdf.in new file mode 100644 index 0000000..73c9d37 --- a/dev/null +++ b/install.rdf.in | |||
@@ -0,0 +1,28 @@ | |||
1 | <?xml version="1.0"?> | ||
2 | <RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#" | ||
3 | xmlns:em="http://www.mozilla.org/2004/em-rdf#"> | ||
4 | |||
5 | <Description about="urn:mozilla:install-manifest"> | ||
6 | |||
7 | <em:id>@MOZ_EXT_ID@</em:id> | ||
8 | <em:name>Fireflix</em:name> | ||
9 | <em:version>@VERSION@</em:version> | ||
10 | <em:description>Flickr management tool</em:description> | ||
11 | <em:creator>Klever Group; http://www.klever.net/</em:creator> | ||
12 | <em:homepageURL>http://kin.klever.net/</em:homepageURL> | ||
13 | <em:iconURL>chrome://fireflix/content/icons/32x32/fireflix.png</em:iconURL> | ||
14 | <em:updateURL>http://kin.klever.net/fireflix/update?v=@VERSION@</em:updateURL> | ||
15 | <em:aboutURL>chrome://fireflix/content/about.xul</em:aboutURL> | ||
16 | |||
17 | <!-- Firefox --> | ||
18 | <em:targetApplication> | ||
19 | <Description> | ||
20 | <em:id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</em:id> | ||
21 | <em:minVersion>1.5</em:minVersion> | ||
22 | <em:maxVersion>1.5.0.7</em:maxVersion> | ||
23 | </Description> | ||
24 | </em:targetApplication> | ||
25 | |||
26 | </Description> | ||
27 | |||
28 | </RDF> | ||
diff --git a/locale/Makefile.am b/locale/Makefile.am new file mode 100644 index 0000000..0e62920 --- a/dev/null +++ b/locale/Makefile.am | |||
@@ -0,0 +1,10 @@ | |||
1 | LOCALES=en-US | ||
2 | nobase_xpichromelocale_DATA = \ | ||
3 | $(addsuffix /fireflix.dtd, \ | ||
4 | ${LOCALES} \ | ||
5 | ) \ | ||
6 | $(addsuffix /fireflix.properties, \ | ||
7 | ${LOCALES} \ | ||
8 | ) | ||
9 | |||
10 | EXTRA_DIST = ${nobase_xpichromelocale_DATA} | ||
diff --git a/locale/en-US/fireflix.dtd b/locale/en-US/fireflix.dtd new file mode 100644 index 0000000..2b6e72a --- a/dev/null +++ b/locale/en-US/fireflix.dtd | |||
@@ -0,0 +1,79 @@ | |||
1 | <!ENTITY % autoconf SYSTEM "chrome://fireflix/content/autoconf.dtd"> | ||
2 | %autoconf; | ||
3 | |||
4 | <!-- About Box --> | ||
5 | |||
6 | <!ENTITY aboutFireflix "About Fireflix" > | ||
7 | <!ENTITY about.ok.label "OK"> | ||
8 | <!ENTITY about.license.label "License"> | ||
9 | <!ENTITY about.license.tip "Show copying policy"> | ||
10 | |||
11 | <!-- COPYING --> | ||
12 | |||
13 | <!ENTITY copying.title "Filreflix: copying policy"> | ||
14 | |||
15 | <!-- Sidebar --> | ||
16 | |||
17 | <!ENTITY panel.auth_info "Authorization info"> | ||
18 | <!ENTITY panel.no_auth_info "No auth info available"> | ||
19 | <!ENTITY panel.auth_button "Authorize"> | ||
20 | <!ENTITY panel.auth_complete_button "Authorization complete"> | ||
21 | <!ENTITY panel.flickr_button.label "Flickr"> | ||
22 | <!ENTITY panel.flickr_button.tip "Open Flickr in new tab"> | ||
23 | |||
24 | <!ENTITY panel.tabs.search "Search" > | ||
25 | <!ENTITY panel.tabs.sets "Sets" > | ||
26 | <!ENTITY panel.tabs.tags "Tags" > | ||
27 | <!ENTITY panel.tabs.upload "Upload" > | ||
28 | |||
29 | <!ENTITY panel.search.cmd_search.label "Search" > | ||
30 | <!ENTITY panel.search.search_for.label "Search for:" > | ||
31 | <!ENTITY panel.search.mode.tagsonly.label "tags"> | ||
32 | <!ENTITY panel.search.mode.tagsonly.tip "Search tags only"> | ||
33 | <!ENTITY panel.search.mode.mine.label "mine"> | ||
34 | <!ENTITY panel.search.col.title.label "Title"> | ||
35 | <!ENTITY panel.search.cmd_search_open.label "Open"> | ||
36 | |||
37 | <!ENTITY panel.sets.name.label "Set"> | ||
38 | <!ENTITY panel.sets.name.tip "Photoset name"> | ||
39 | <!ENTITY panel.sets.photos.label "Photos"> | ||
40 | <!ENTITY panel.sets.photos.tip "Number of photos in set"> | ||
41 | |||
42 | <!ENTITY panel.sets.cmd_refresh_sets "Refresh"> | ||
43 | <!ENTITY panel.sets.cmd_properties "Properties"> | ||
44 | |||
45 | <!ENTITY panel.sets.generate_html "Generate HTML"> | ||
46 | |||
47 | <!ENTITY panel.setphotos.title.label "Title"> | ||
48 | <!ENTITY panel.setphotos.title.tip "Picture title"> | ||
49 | <!ENTITY panel.setphotos.taken.label "Taken"> | ||
50 | <!ENTITY panel.setphotos.taken.tip "When the picture was taken"> | ||
51 | <!ENTITY panel.setphotos.upload.label "Uploaded"> | ||
52 | <!ENTITY panel.setphotos.upload.tip "When the picure was uploaded"> | ||
53 | |||
54 | <!ENTITY panel.tagslist.tag.label "Tag"> | ||
55 | |||
56 | <!ENTITY panel.uploadlist.file.label "File name"> | ||
57 | <!ENTITY panel.uploadlist.title.label "Title"> | ||
58 | <!ENTITY panel.uploadlist.status.label "Status"> | ||
59 | |||
60 | <!ENTITY panel.upload_props.filename.label "File:"> | ||
61 | <!ENTITY panel.upload_props.title.label "Title:"> | ||
62 | <!ENTITY panel.upload_props.tags.label "Tags:"> | ||
63 | |||
64 | <!ENTITY panel.uploads.upload.label "Upload"> | ||
65 | <!ENTITY panel.uploads.clear.label "Clear"> | ||
66 | <!ENTITY panel.uploads.remove.label "Remove"> | ||
67 | <!ENTITY panel.uploads.add.label "Add"> | ||
68 | <!ENTITY panel.uploads.generate_html "Generate HTML"> | ||
69 | |||
70 | <!ENTITY generated.title "Fireflix: Generated content"> | ||
71 | <!ENTITY generated.copy "copy"> | ||
72 | |||
73 | <!ENTITY browser.sidebar.label "Fireflix"> | ||
74 | <!ENTITY browser.sidebar.title "Fireflix"> | ||
75 | |||
76 | <!ENTITY photosetprops.title "Photoset properties"> | ||
77 | <!ENTITY photosetprops.set_title.label "Photoset title:"> | ||
78 | <!ENTITY photosetprops.set_desc.label "Photoset description:"> | ||
79 | |||
diff --git a/locale/en-US/fireflix.properties b/locale/en-US/fireflix.properties new file mode 100644 index 0000000..7caa12f --- a/dev/null +++ b/locale/en-US/fireflix.properties | |||
@@ -0,0 +1,11 @@ | |||
1 | postUploadPhotoset=Create a new photoset for uploaded photos (cancel if you don't want to create a photoset) | ||
2 | |||
3 | menutitle_Images=Images | ||
4 | menutitle_Links=Linked to… | ||
5 | urltype_s=Small square (75x75) | ||
6 | urltype_t=Thumbnail (fits in 100x100) | ||
7 | urltype_m=Small (fits in 240x240) | ||
8 | urltype__=Medium (fits in 500x500) | ||
9 | urltype_b=Large (fits in 1024x1024) | ||
10 | urltype_o=Original image | ||
11 | urltype_p=Flickr photo URL | ||
diff --git a/update.rdf.in b/update.rdf.in new file mode 100644 index 0000000..7a78470 --- a/dev/null +++ b/update.rdf.in | |||
@@ -0,0 +1,26 @@ | |||
1 | <?xml version="1.0"?> | ||
2 | <RDF:RDF | ||
3 | xmlns:RDF="http://www.w3.org/1999/02/22-rdf-syntax-ns#" | ||
4 | xmlns:em="http://www.mozilla.org/2004/em-rdf#"> | ||
5 | |||
6 | <RDF:Description about="urn:mozilla:extension:@MOZ_EXT_ID@"> | ||
7 | <em:updates> | ||
8 | <RDF:Seq> | ||
9 | <RDF:li resource="urn:mozilla:extension:@MOZ_EXT_ID@:@VERSION@"/> | ||
10 | </RDF:Seq> | ||
11 | </em:updates> | ||
12 | </RDF:Description> | ||
13 | |||
14 | <RDF:Description about="urn:mozilla:extension:@MOZ_EXT_ID@:@VERSION@"> | ||
15 | <em:version>@VERSION@</em:version> | ||
16 | <em:targetApplication> | ||
17 | <Description> | ||
18 | <em:id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</em:id> | ||
19 | <em:minVersion>1.5</em:minVersion> | ||
20 | <em:maxVersion>1.5.0.7</em:maxVersion> | ||
21 | <em:updateLink>http://kin.klever.net/dist/@PACKAGE@-@VERSION@.xpi</em:updateLink> | ||
22 | </Description> | ||
23 | </em:targetApplication> | ||
24 | </RDF:Description> | ||
25 | |||
26 | </RDF:RDF> | ||