]>
git.wh0rd.org - tt-rss.git/blob - functions.js
1 var notify_silent
= false ;
2 var loading_progress
= 0 ;
3 var sanity_check_done
= false ;
5 /* add method to remove element from array */
7 Array
. prototype . remove = function ( s
) {
8 for ( var i
= 0 ; i
< this . length
; i
++) {
9 if ( s
== this [ i
]) this . splice ( i
, 1 );
13 /* create console.log if it doesn't exist */
15 if (! window
. console
) console
= {};
16 console
. log
= console
. log
|| function ( msg
) { };
17 console
. warn
= console
. warn
|| function ( msg
) { };
18 console
. error
= console
. error
|| function ( msg
) { };
20 function exception_error ( location
, e
, ext_info
) {
21 var msg
= format_exception_error ( location
, e
);
23 if (! ext_info
) ext_info
= false ;
28 if ( ext_info
. responseText
) {
29 ext_info
= ext_info
. responseText
;
33 var content
= "<div class= \" fatalError \" >" +
34 "<pre>" + msg
+ "</pre>" ;
36 content
+= "<form name= \" exceptionForm \" id= \" exceptionForm \" target= \" _blank \" " +
37 "action= \" http://tt-rss.org/report.php \" method= \" POST \" >" ;
39 content
+= "<textarea style= \" display : none \" name= \" message \" >" + msg
+ "</textarea>" ;
40 content
+= "<textarea style= \" display : none \" name= \" params \" >N/A</textarea>" ;
43 content
+= "<div><b>Additional information:</b></div>" +
44 "<textarea name= \" xinfo \" readonly= \" 1 \" >" + ext_info
+ "</textarea>" ;
47 content
+= "<div><b>Stack trace:</b></div>" +
48 "<textarea name= \" stack \" readonly= \" 1 \" >" + e
. stack
+ "</textarea>" ;
54 content
+= "<div class='dlgButtons'>" ;
56 content
+= "<button dojoType= \" dijit.form.Button \" " +
57 "onclick= \" dijit.byId('exceptionDlg').report() \" >" +
58 __ ( 'Report to tt-rss.org' ) + "</button> " ;
59 content
+= "<button dojoType= \" dijit.form.Button \" " +
60 "onclick= \" dijit.byId('exceptionDlg').hide() \" >" +
61 __ ( 'Close' ) + "</button>" ;
64 if ( dijit
. byId ( "exceptionDlg" ))
65 dijit
. byId ( "exceptionDlg" ). destroyRecursive ();
67 var dialog
= new dijit
. Dialog ({
69 title
: "Unhandled exception" ,
70 style
: "width: 600px" ,
72 if ( confirm ( __ ( "Are you sure to report this exception to tt-rss.org? The report will include your browser information. Your IP would be saved in the database." ))) {
74 document
. forms
[ 'exceptionForm' ]. params
. value
= $ H ({
75 browserName
: navigator
. appName
,
76 browserVersion
: navigator
. appVersion
,
77 browserPlatform
: navigator
. platform
,
78 browserCookies
: navigator
. cookieEnabled
,
81 document
. forms
[ 'exceptionForm' ]. submit ();
95 function format_exception_error ( location
, e
) {
99 var base_fname
= e
. fileName
. substring ( e
. fileName
. lastIndexOf ( "/" ) + 1 );
101 msg
= "Exception: " + e
. name
+ ", " + e
. message
+
102 " \n Function: " + location
+ "()" +
103 " \n Location: " + base_fname
+ ":" + e
. lineNumber
;
105 } else if ( e
. description
) {
106 msg
= "Exception: " + e
. description
+ " \n Function: " + location
+ "()" ;
108 msg
= "Exception: " + e
+ " \n Function: " + location
+ "()" ;
111 console
. error ( "EXCEPTION: " + msg
);
116 function param_escape ( arg
) {
117 if ( typeof encodeURIComponent
!= 'undefined' )
118 return encodeURIComponent ( arg
);
123 function param_unescape ( arg
) {
124 if ( typeof decodeURIComponent
!= 'undefined' )
125 return decodeURIComponent ( arg
);
127 return unescape ( arg
);
130 var notify_hide_timerid
= false ;
132 function hide_notify () {
135 n
. style
. display
= "none" ;
139 function notify_silent_next () {
140 notify_silent
= true ;
143 function notify_real ( msg
, no_hide
, n_type
) {
146 notify_silent
= false ;
151 var nb
= $( "notify_body" );
153 if (! n
|| ! nb
) return ;
155 if ( notify_hide_timerid
) {
156 window
. clearTimeout ( notify_hide_timerid
);
160 if ( n
. style
. display
== "block" ) {
161 notify_hide_timerid
= window
. setTimeout ( "hide_notify()" , 0 );
165 n
. style
. display
= "block" ;
177 if ( typeof __
!= 'undefined' ) {
182 n
. className
= "notify" ;
183 } else if ( n_type
== 2 ) {
184 n
. className
= "notifyProgress" ;
185 msg
= "<img src='" + getInitParam ( "sign_progress" )+ "'> " + msg
;
186 } else if ( n_type
== 3 ) {
187 n
. className
= "notifyError" ;
188 msg
= "<img src='" + getInitParam ( "sign_excl" )+ "'> " + msg
;
189 } else if ( n_type
== 4 ) {
190 n
. className
= "notifyInfo" ;
191 msg
= "<img src='" + getInitParam ( "sign_info" )+ "'> " + msg
;
194 // msg = "<img src='images/live_com_loading.gif'> " + msg;
199 notify_hide_timerid
= window
. setTimeout ( "hide_notify()" , 3000 );
203 function notify ( msg
, no_hide
) {
204 notify_real ( msg
, no_hide
, 1 );
207 function notify_progress ( msg
, no_hide
) {
208 notify_real ( msg
, no_hide
, 2 );
211 function notify_error ( msg
, no_hide
) {
212 notify_real ( msg
, no_hide
, 3 );
216 function notify_info ( msg
, no_hide
) {
217 notify_real ( msg
, no_hide
, 4 );
220 function setCookie ( name
, value
, lifetime
, path
, domain
, secure
) {
226 d
. setTime ( d
. getTime () + ( lifetime
* 1000 ));
229 console
. log ( "setCookie: " + name
+ " => " + value
+ ": " + d
);
231 int_setCookie ( name
, value
, d
, path
, domain
, secure
);
235 function int_setCookie ( name
, value
, expires
, path
, domain
, secure
) {
236 document
. cookie
= name
+ "=" + escape ( value
) +
237 (( expires
) ? "; expires=" + expires
. toGMTString () : "" ) +
238 (( path
) ? "; path=" + path
: "" ) +
239 (( domain
) ? "; domain=" + domain
: "" ) +
240 (( secure
) ? "; secure" : "" );
243 function delCookie ( name
, path
, domain
) {
244 if ( getCookie ( name
)) {
245 document
. cookie
= name
+ "=" +
246 (( path
) ? ";path=" + path
: "" ) +
247 (( domain
) ? ";domain=" + domain
: "" ) +
248 ";expires=Thu, 01-Jan-1970 00:00:01 GMT" ;
253 function getCookie ( name
) {
255 var dc
= document
. cookie
;
256 var prefix
= name
+ "=" ;
257 var begin
= dc
. indexOf ( "; " + prefix
);
259 begin
= dc
. indexOf ( prefix
);
260 if ( begin
!= 0 ) return null ;
265 var end
= document
. cookie
. indexOf ( ";" , begin
);
269 return unescape ( dc
. substring ( begin
+ prefix
. length
, end
));
272 function gotoPreferences () {
273 document
. location
. href
= "prefs.php" ;
276 function gotoMain () {
277 document
. location
. href
= "tt-rss.php" ;
280 function gotoExportOpml ( filename
, settings
) {
281 tmp
= settings
? 1 : 0 ;
282 document
. location
. href
= "opml.php?op=Export&filename=" + filename
+ "&settings=" + tmp
;
286 /** * @(#)isNumeric.js * * Copyright (c) 2000 by Sundar Dorai-Raj
287 * * @author Sundar Dorai-Raj
288 * * Email: sdoraira@vt.edu
289 * * This program is free software; you can redistribute it and/or
290 * * modify it under the terms of the GNU General Public License
291 * * as published by the Free Software Foundation; either version 2
292 * * of the License, or (at your option) any later version,
293 * * provided that any use properly credits the author.
294 * * This program is distributed in the hope that it will be useful,
295 * * but WITHOUT ANY WARRANTY; without even the implied warranty of
296 * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
297 * * GNU General Public License for more details at http://www.gnu.org * * */
299 var numbers
= ".0123456789" ;
300 function isNumeric ( x
) {
301 // is x a String or a character?
303 // remove negative sign
305 for ( j
= 0 ; j
< x
. length
; j
++) {
306 // call isNumeric recursively for each character
307 number
= isNumeric ( x
. substring ( j
, j
+ 1 ));
308 if (! number
) return number
;
313 // if x is number return true
314 if ( numbers
. indexOf ( x
)>= 0 ) return true ;
320 function toggleSelectRowById ( sender
, id
) {
322 return toggleSelectRow ( sender
, row
);
325 function toggleSelectListRow ( sender
) {
326 var row
= sender
. parentNode
;
327 return toggleSelectRow ( sender
, row
);
330 /* this is for dijit Checkbox */
331 function toggleSelectListRow2 ( sender
) {
332 var row
= sender
. domNode
. parentNode
;
333 return toggleSelectRow ( sender
, row
);
336 function tSR ( sender
, row
) {
337 return toggleSelectRow ( sender
, row
);
340 /* this is for dijit Checkbox */
341 function toggleSelectRow2 ( sender
, row
) {
343 if (! row
) row
= sender
. domNode
. parentNode
. parentNode
;
345 if ( sender
. checked
&& ! row
. hasClassName ( 'Selected' ))
346 row
. addClassName ( 'Selected' );
348 row
. removeClassName ( 'Selected' );
352 function toggleSelectRow ( sender
, row
) {
354 if (! row
) row
= sender
. parentNode
. parentNode
;
356 if ( sender
. checked
&& ! row
. hasClassName ( 'Selected' ))
357 row
. addClassName ( 'Selected' );
359 row
. removeClassName ( 'Selected' );
362 function checkboxToggleElement ( elem
, id
) {
364 Effect
. Appear ( id
, { duration
: 0.5 });
366 Effect
. Fade ( id
, { duration
: 0.5 });
370 function dropboxSelect ( e
, v
) {
371 for ( i
= 0 ; i
< e
. length
; i
++) {
372 if ( e
[ i
]. value
== v
) {
379 function getURLParam ( param
){
380 return String ( window
. location
. href
). parseQuery ()[ param
];
383 function leading_zero ( p
) {
385 if ( s
. length
== 1 ) s
= "0" + s
;
389 function make_timestamp () {
392 return leading_zero ( d
. getHours ()) + ":" + leading_zero ( d
. getMinutes ()) +
393 ":" + leading_zero ( d
. getSeconds ());
397 function closeErrorBox () {
399 if ( Element
. visible ( "errorBoxShadow" )) {
400 Element
. hide ( "dialog_overlay" );
401 Element
. hide ( "errorBoxShadow" );
407 function closeInfoBox ( cleanup
) {
409 dialog
= dijit
. byId ( "infoBox" );
411 if ( dialog
) dialog
. hide ();
414 //exception_error("closeInfoBox", e);
420 function displayDlg ( id
, param
, callback
) {
422 notify_progress ( "Loading, please wait..." , true );
424 var query
= "?op=dlg&id=" +
425 param_escape ( id
) + "¶m=" + param_escape ( param
);
427 new Ajax
. Request ( "backend.php" , {
429 onComplete : function ( transport
) {
430 infobox_callback2 ( transport
);
431 if ( callback
) callback ( transport
);
437 function infobox_callback2 ( transport
) {
441 if ( dijit
. byId ( "infoBox" )) {
442 dialog
= dijit
. byId ( "infoBox" );
445 //console.log("infobox_callback2");
449 var dtitle
= "Dialog" ;
451 var dlg
= transport
. responseXML
. getElementsByTagName ( "dlg" )[ 0 ];
453 var title
= transport
. responseXML
. getElementsByTagName ( "title" )[ 0 ];
455 title
= title
. firstChild
. nodeValue
;
457 var content
= transport
. responseXML
. getElementsByTagName ( "content" )[ 0 ];
459 content
= content
. firstChild
. nodeValue
;
462 dialog
= new dijit
. Dialog ({
465 style
: "width: 600px" ,
466 onCancel : function () {
469 onExecute : function () {
472 onClose : function () {
477 dialog
. attr ( 'title' , title
);
478 dialog
. attr ( 'content' , content
);
485 exception_error ( "infobox_callback2" , e
);
489 function filterCR ( e
, f
)
494 key
= window
. event
. keyCode
; //IE
496 key
= e
. which
; //firefox
499 if ( typeof f
!= 'undefined' ) {
510 function getInitParam ( key
) {
511 return init_params
[ key
];
514 function setInitParam ( key
, value
) {
515 init_params
[ key
] = value
;
518 function fatalError ( code
, msg
, ext_info
) {
522 window
. location
. href
= "tt-rss.php" ;
523 } else if ( code
== 5 ) {
524 window
. location
. href
= "db-updater.php" ;
527 if ( msg
== "" ) msg
= "Unknown error" ;
530 if ( ext_info
. responseText
) {
531 ext_info
= ext_info
. responseText
;
535 if ( ERRORS
&& ERRORS
[ code
] && ! msg
) {
539 var content
= "<div><b>Error code:</b> " + code
+ "</div>" +
540 "<p>" + msg
+ "</p>" ;
543 content
= content
+ "<div><b>Additional information:</b></div>" +
544 "<textarea style='width: 100%' readonly= \" 1 \" >" +
545 ext_info
+ "</textarea>" ;
548 var dialog
= new dijit
. Dialog ({
549 title
: "Fatal error" ,
550 style
: "width: 600px" ,
560 exception_error ( "fatalError" , e
);
564 function filterDlgCheckType ( sender
) {
568 var ftype
= sender
. value
;
570 // if selected filter type is 5 (Date) enable the modifier dropbox
572 Element
. show ( "filterDlg_dateModBox" );
573 Element
. show ( "filterDlg_dateChkBox" );
575 Element
. hide ( "filterDlg_dateModBox" );
576 Element
. hide ( "filterDlg_dateChkBox" );
581 exception_error ( "filterDlgCheckType" , e
);
586 function filterDlgCheckAction ( sender
) {
590 var action
= sender
. value
;
592 var action_param
= $( "filterDlg_paramBox" );
595 console
. log ( "filterDlgCheckAction: can't find action param box!" );
599 // if selected action supports parameters, enable params field
600 if ( action
== 4 || action
== 6 || action
== 7 ) {
601 new Effect
. Appear ( action_param
, { duration
: 0.5 });
603 Element
. show ( dijit
. byId ( "filterDlg_actionParam" ). domNode
);
604 Element
. hide ( dijit
. byId ( "filterDlg_actionParamLabel" ). domNode
);
606 Element
. show ( dijit
. byId ( "filterDlg_actionParamLabel" ). domNode
);
607 Element
. hide ( dijit
. byId ( "filterDlg_actionParam" ). domNode
);
610 Element
. hide ( action_param
);
614 exception_error ( "filterDlgCheckAction" , e
);
619 function filterDlgCheckDate () {
621 var dialog
= dijit
. byId ( "filterEditDlg" );
623 var reg_exp
= dialog
. attr ( 'value' ). reg_exp
;
625 var query
= "?op=rpc&subop=checkDate&date=" + reg_exp
;
627 new Ajax
. Request ( "backend.php" , {
629 onComplete : function ( transport
) {
631 var reply
= JSON
. parse ( transport
. responseText
);
633 if ( reply
[ 'result' ] == true ) {
634 alert ( __ ( "Date syntax appears to be correct:" ) + " " + reply
[ 'date' ]);
637 alert ( __ ( "Date syntax is incorrect." ));
644 exception_error ( "filterDlgCheckDate" , e
);
648 function explainError ( code
) {
649 return displayDlg ( "explainError" , code
);
652 function displayHelpInfobox ( topic_id
) {
654 var url
= "backend.php?op=help&tid=" + param_escape ( topic_id
);
656 var w
= window
. open ( url
, "ttrss_help" ,
657 "status=0,toolbar=0,location=0,width=450,height=500,scrollbars=1,menubar=0" );
661 function loading_set_progress ( p
) {
663 loading_progress
+= p
;
665 if ( dijit
. byId ( "loading_bar" ))
666 dijit
. byId ( "loading_bar" ). update ({ progress
: loading_progress
});
668 if ( loading_progress
>= 90 )
672 exception_error ( "loading_set_progress" , e
);
676 function remove_splash () {
678 if ( Element
. visible ( "overlay" )) {
679 console
. log ( "about to remove splash, OMG!" );
680 Element
. hide ( "overlay" );
681 console
. log ( "removed splash!" );
685 function transport_error_check ( transport
) {
687 if ( transport
. responseXML
) {
688 var error
= transport
. responseXML
. getElementsByTagName ( "error" )[ 0 ];
691 var code
= error
. getAttribute ( "error-code" );
692 var msg
= error
. getAttribute ( "error-msg" );
694 fatalError ( code
, msg
);
700 exception_error ( "check_for_error_xml" , e
);
705 function strip_tags ( s
) {
706 return s
. replace ( /<\/?[^>]+(>|$)/g , "" );
709 function truncate_string ( s
, length
) {
710 if (! length
) length
= 30 ;
711 var tmp
= s
. substring ( 0 , length
);
712 if ( s
. length
> length
) tmp
+= "…" ;
716 function hotkey_prefix_timeout () {
719 var date
= new Date ();
720 var ts
= Math
. round ( date
. getTime () / 1000 );
722 if ( hotkey_prefix_pressed
&& ts
- hotkey_prefix_pressed
>= 5 ) {
723 console
. log ( "hotkey_prefix seems to be stuck, aborting" );
724 hotkey_prefix_pressed
= false ;
725 hotkey_prefix
= false ;
726 Element
. hide ( 'cmdline' );
729 setTimeout ( "hotkey_prefix_timeout()" , 1000 );
732 exception_error ( "hotkey_prefix_timeout" , e
);
736 function hideAuxDlg () {
738 Element
. hide ( 'auxDlg' );
740 exception_error ( "hideAuxDlg" , e
);
745 function uploadIconHandler ( rc
) {
749 notify_info ( "Upload complete." );
750 if ( inPreferences ()) {
753 setTimeout ( 'updateFeedList(false, false)' , 50 );
757 notify_error ( "Upload failed: icon is too big." );
760 notify_error ( "Upload failed." );
765 exception_error ( "uploadIconHandler" , e
);
769 function removeFeedIcon ( id
) {
773 if ( confirm ( __ ( "Remove stored feed icon?" ))) {
774 var query
= "backend.php?op=pref-feeds&subop=removeicon&feed_id=" + param_escape ( id
);
778 notify_progress ( "Removing feed icon..." , true );
780 new Ajax
. Request ( "backend.php" , {
782 onComplete : function ( transport
) {
783 notify_info ( "Feed icon removed." );
784 if ( inPreferences ()) {
787 setTimeout ( 'updateFeedList(false, false)' , 50 );
794 exception_error ( "uploadFeedIcon" , e
);
798 function uploadFeedIcon () {
802 var file
= $( "icon_file" );
804 if ( file
. value
. length
== 0 ) {
805 alert ( __ ( "Please select an image file to upload." ));
807 if ( confirm ( __ ( "Upload new icon for this feed?" ))) {
808 notify_progress ( "Uploading, please wait..." , true );
816 exception_error ( "uploadFeedIcon" , e
);
820 function addLabel ( select
, callback
) {
824 var caption
= prompt ( __ ( "Please enter label caption:" ), "" );
826 if ( caption
!= undefined ) {
829 alert ( __ ( "Can't create label: missing caption." ));
833 var query
= "?op=pref-labels&subop=add&caption=" +
834 param_escape ( caption
);
837 query
+= "&output=select" ;
839 notify_progress ( "Loading, please wait..." , true );
841 if ( inPreferences () && ! select
) active_tab
= "labelConfig" ;
843 new Ajax
. Request ( "backend.php" , {
845 onComplete : function ( transport
) {
848 } else if ( inPreferences ()) {
858 exception_error ( "addLabel" , e
);
862 function quickAddFeed () {
864 var query
= "backend.php?op=dlg&id=quickAddFeed" ;
866 if ( dijit
. byId ( "feedAddDlg" ))
867 dijit
. byId ( "feedAddDlg" ). destroyRecursive ();
869 var dialog
= new dijit
. Dialog ({
871 title
: __ ( "Subscribe to Feed" ),
872 style
: "width: 600px" ,
873 execute : function () {
874 if ( this . validate ()) {
875 console
. log ( dojo
. objectToQuery ( this . attr ( 'value' )));
877 var feed_url
= this . attr ( 'value' ). feed
;
879 notify_progress ( __ ( "Subscribing to feed..." ), true );
881 new Ajax
. Request ( "backend.php" , {
882 parameters
: dojo
. objectToQuery ( this . attr ( 'value' )),
883 onComplete : function ( transport
) {
886 var reply
= JSON
. parse ( transport
. responseText
);
888 var rc
= parseInt ( reply
[ 'result' ]);
892 console
. log ( "GOT RC: " + rc
);
897 notify_info ( __ ( "Subscribed to %s" ). replace ( "%s" , feed_url
));
902 alert ( __ ( "Specified URL seems to be invalid." ));
905 alert ( __ ( "Specified URL doesn't seem to contain any feeds." ));
908 notify_progress ( "Searching for feed urls..." , true );
910 new Ajax
. Request ( "backend.php" , {
911 parameters
: 'op=rpc&subop=extractfeedurls&url=' + param_escape ( feed_url
),
912 onComplete : function ( transport
, dialog
, feed_url
) {
916 var reply
= JSON
. parse ( transport
. responseText
);
918 var feeds
= reply
[ 'urls' ];
920 console
. log ( transport
. responseText
);
922 var select
= dijit
. byId ( "feedDlg_feedContainerSelect" );
924 while ( select
. getOptions (). length
> 0 )
925 select
. removeOption ( 0 );
928 for ( var feedUrl
in feeds
) {
929 select
. addOption ({ value
: feedUrl
, label
: feeds
[ feedUrl
]});
933 // if (count > 5) count = 5;
934 // select.size = count;
936 Effect
. Appear ( 'feedDlg_feedsContainer' , { duration
: 0.5 });
941 alert ( __ ( "Couldn't download the specified URL." ));
944 alert ( __ ( "You are already subscribed to this feed." ));
949 exception_error ( "subscribeToFeed" , e
, transport
);
960 exception_error ( "quickAddFeed" , e
);
964 function quickAddFilter () {
966 var query
= "backend.php?op=dlg&id=quickAddFilter" ;
968 if ( dijit
. byId ( "filterEditDlg" ))
969 dijit
. byId ( "filterEditDlg" ). destroyRecursive ();
971 dialog
= new dijit
. Dialog ({
973 title
: __ ( "Create Filter" ),
974 style
: "width: 600px" ,
976 if ( this . validate ()) {
978 if ( dijit
. byId ( "filterTestDlg" ))
979 dijit
. byId ( "filterTestDlg" ). destroyRecursive ();
981 tdialog
= new dijit
. Dialog ({
983 title
: __ ( "Filter Test Results" ),
984 style
: "width: 600px" ,
985 href
: "backend.php?savemode=test&" +
986 dojo
. objectToQuery ( dialog
. attr ( 'value' )),
993 execute : function () {
994 if ( this . validate ()) {
996 var query
= "?op=rpc&subop=verifyRegexp®_exp=" +
997 param_escape ( dialog
. attr ( 'value' ). reg_exp
);
999 notify_progress ( "Verifying regular expression..." );
1001 new Ajax
. Request ( "backend.php" , {
1003 onComplete : function ( transport
) {
1004 var reply
= JSON
. parse ( transport
. responseText
);
1009 if (! reply
[ 'status' ]) {
1010 alert ( "Match regular expression seems to be invalid." );
1013 notify_progress ( "Saving data..." , true );
1015 console
. log ( dojo
. objectToQuery ( dialog
. attr ( 'value' )));
1017 new Ajax
. Request ( "backend.php" , {
1018 parameters
: dojo
. objectToQuery ( dialog
. attr ( 'value' )),
1019 onComplete : function ( transport
) {
1021 notify_info ( transport
. responseText
);
1022 if ( inPreferences ()) {
1035 exception_error ( "quickAddFilter" , e
);
1039 function resetPubSub ( feed_id
, title
) {
1041 var msg
= __ ( "Reset subscription? Tiny Tiny RSS will try to subscribe to the notification hub again on next feed update." ). replace ( "%s" , title
);
1043 if ( title
== undefined || confirm ( msg
)) {
1044 notify_progress ( "Loading, please wait..." );
1046 var query
= "?op=pref-feeds&quiet=1&subop=resetPubSub&ids=" + feed_id
;
1048 new Ajax
. Request ( "backend.php" , {
1050 onComplete : function ( transport
) {
1051 dijit
. byId ( "pubsubReset_Btn" ). attr ( 'disabled' , true );
1052 notify_info ( "Subscription reset." );
1060 function unsubscribeFeed ( feed_id
, title
) {
1062 var msg
= __ ( "Unsubscribe from %s?" ). replace ( "%s" , title
);
1064 if ( title
== undefined || confirm ( msg
)) {
1065 notify_progress ( "Removing feed..." );
1067 var query
= "?op=pref-feeds&quiet=1&subop=remove&ids=" + feed_id
;
1069 new Ajax
. Request ( "backend.php" , {
1071 onComplete : function ( transport
) {
1073 if ( dijit
. byId ( "feedEditDlg" )) dijit
. byId ( "feedEditDlg" ). hide ();
1075 if ( inPreferences ()) {
1078 if ( feed_id
== getActiveFeedId ())
1079 setTimeout ( "viewfeed(-5)" , 100 );
1089 function backend_sanity_check_callback ( transport
) {
1093 if ( sanity_check_done
) {
1094 fatalError ( 11 , "Sanity check request received twice. This can indicate " +
1095 "presence of Firebug or some other disrupting extension. " +
1096 "Please disable it and try again." );
1100 var reply
= JSON
. parse ( transport
. responseText
);
1103 fatalError ( 3 , "Sanity check: invalid RPC reply" , transport
. responseText
);
1107 var error_code
= reply
[ 'error' ][ 'code' ];
1109 if ( error_code
&& error_code
!= 0 ) {
1110 return fatalError ( error_code
, reply
[ 'error' ][ 'message' ]);
1113 console
. log ( "sanity check ok" );
1115 var params
= reply
[ 'init-params' ];
1118 console
. log ( 'reading init-params...' );
1123 console
. log ( "IP: " + k
+ " => " + v
);
1127 init_params
= params
;
1130 sanity_check_done
= true ;
1132 init_second_stage ();
1135 exception_error ( "backend_sanity_check_callback" , e
, transport
);
1139 /*function has_local_storage() {
1141 return 'sessionStorage' in window && window['sessionStorage'] != null;
1147 function catSelectOnChange ( elem
) {
1149 /* var value = elem[elem.selectedIndex].value;
1150 var def = elem.getAttribute('default');
1152 if (value == "ADD_CAT") {
1155 dropboxSelect(elem, def);
1157 elem.selectedIndex = 0;
1163 exception_error ( "catSelectOnChange" , e
);
1167 function quickAddCat ( elem
) {
1169 var cat
= prompt ( __ ( "Please enter category title:" ));
1173 var query
= "?op=rpc&subop=quickAddCat&cat=" + param_escape ( cat
);
1175 notify_progress ( "Loading, please wait..." , true );
1177 new Ajax
. Request ( "backend.php" , {
1179 onComplete : function ( transport
) {
1180 var response
= transport
. responseXML
;
1181 var select
= response
. getElementsByTagName ( "select" )[ 0 ];
1182 var options
= select
. getElementsByTagName ( "option" );
1184 dropbox_replace_options ( elem
, options
);
1193 exception_error ( "quickAddCat" , e
);
1197 function genUrlChangeKey ( feed
, is_cat
) {
1200 var ok
= confirm ( __ ( "Generate new syndication address for this feed?" ));
1204 notify_progress ( "Trying to change address..." , true );
1206 var query
= "?op=rpc&subop=regenFeedKey&id=" + param_escape ( feed
) +
1207 "&is_cat=" + param_escape ( is_cat
);
1209 new Ajax
. Request ( "backend.php" , {
1211 onComplete : function ( transport
) {
1212 var reply
= JSON
. parse ( transport
. responseText
);
1213 var new_link
= reply
. link
;
1215 var e
= $( 'gen_feed_url' );
1219 e
. innerHTML
= e
. innerHTML
. replace ( /\&key=.*$/ ,
1220 "&key=" + new_link
);
1222 e
. href
= e
. href
. replace ( /\&key=.*$/ ,
1223 "&key=" + new_link
);
1225 new Effect
. Highlight ( e
);
1230 notify_error ( "Could not change feed URL." );
1235 exception_error ( "genUrlChangeKey" , e
);
1240 function labelSelectOnChange ( elem
) {
1242 /* var value = elem[elem.selectedIndex].value;
1243 var def = elem.getAttribute('default');
1245 if (value == "ADD_LABEL") {
1248 dropboxSelect(elem, def);
1250 elem.selectedIndex = 0;
1252 addLabel(elem, function(transport) {
1256 var response = transport.responseXML;
1257 var select = response.getElementsByTagName("select")[0];
1258 var options = select.getElementsByTagName("option");
1260 dropbox_replace_options(elem, options);
1264 exception_error("addLabel", e);
1270 exception_error ( "labelSelectOnChange" , e
);
1274 function dropbox_replace_options ( elem
, options
) {
1277 while ( elem
. hasChildNodes ())
1278 elem
. removeChild ( elem
. firstChild
);
1282 for ( var i
= 0 ; i
< options
. length
; i
++) {
1283 var text
= options
[ i
]. firstChild
. nodeValue
;
1284 var value
= options
[ i
]. getAttribute ( "value" );
1286 if ( value
== undefined ) value
= text
;
1288 var issel
= options
[ i
]. getAttribute ( "selected" ) == "1" ;
1290 var option
= new Option ( text
, value
, issel
);
1292 if ( options
[ i
]. getAttribute ( "disabled" ))
1293 option
. setAttribute ( "disabled" , true );
1295 elem
. insert ( option
);
1297 if ( issel
) sel_idx
= i
;
1300 // Chrome doesn't seem to just select stuff when you pass new Option(x, y, true)
1301 if ( sel_idx
>= 0 ) elem
. selectedIndex
= sel_idx
;
1304 exception_error ( "dropbox_replace_options" , e
);
1308 // mode = all, none, invert
1309 function selectTableRows ( id
, mode
) {
1311 var rows
= $( id
). rows
;
1313 for ( var i
= 0 ; i
< rows
. length
; i
++) {
1317 if ( row
. id
&& row
. className
) {
1318 var bare_id
= row
. id
. replace ( /^[A-Z]*?-/ , "" );
1319 var inputs
= rows
[ i
]. getElementsByTagName ( "input" );
1321 for ( var j
= 0 ; j
< inputs
. length
; j
++) {
1322 var input
= inputs
[ j
];
1324 if ( input
. getAttribute ( "type" ) == "checkbox" &&
1325 input
. id
. match ( bare_id
)) {
1333 var issel
= row
. hasClassName ( "Selected" );
1335 if ( mode
== "all" && ! issel
) {
1336 row
. addClassName ( "Selected" );
1338 } else if ( mode
== "none" && issel
) {
1339 row
. removeClassName ( "Selected" );
1341 } else if ( mode
== "invert" ) {
1344 row
. removeClassName ( "Selected" );
1347 row
. addClassName ( "Selected" );
1356 exception_error ( "selectTableRows" , e
);
1361 function getSelectedTableRowIds ( id
) {
1365 var elem_rows
= $( id
). rows
;
1367 for ( i
= 0 ; i
< elem_rows
. length
; i
++) {
1368 if ( elem_rows
[ i
]. hasClassName ( "Selected" )) {
1369 var bare_id
= elem_rows
[ i
]. id
. replace ( /^[A-Z]*?-/ , "" );
1375 exception_error ( "getSelectedTableRowIds" , e
);
1381 function editFeed ( feed
, event
) {
1384 return alert ( __ ( "You can't edit this kind of feed." ));
1386 var query
= "backend.php?op=pref-feeds&subop=editfeed&id=" +
1391 if ( dijit
. byId ( "feedEditDlg" ))
1392 dijit
. byId ( "feedEditDlg" ). destroyRecursive ();
1394 dialog
= new dijit
. Dialog ({
1396 title
: __ ( "Edit Feed" ),
1397 style
: "width: 600px" ,
1398 execute : function () {
1399 if ( this . validate ()) {
1400 // console.log(dojo.objectToQuery(this.attr('value')));
1402 notify_progress ( "Saving data..." , true );
1404 new Ajax
. Request ( "backend.php" , {
1405 parameters
: dojo
. objectToQuery ( dialog
. attr ( 'value' )),
1406 onComplete : function ( transport
) {
1418 exception_error ( "editFeed" , e
);
1422 function feedBrowser () {
1424 var query
= "backend.php?op=dlg&id=feedBrowser" ;
1426 if ( dijit
. byId ( "feedAddDlg" ))
1427 dijit
. byId ( "feedAddDlg" ). hide ();
1429 if ( dijit
. byId ( "feedBrowserDlg" ))
1430 dijit
. byId ( "feedBrowserDlg" ). destroyRecursive ();
1432 var dialog
= new dijit
. Dialog ({
1433 id
: "feedBrowserDlg" ,
1434 title
: __ ( "More Feeds" ),
1435 style
: "width: 600px" ,
1436 getSelectedFeedIds : function () {
1437 var list
= $$( "#browseFeedList li[id*=FBROW]" );
1438 var selected
= new Array ();
1440 list
. each ( function ( child
) {
1441 var id
= child
. id
. replace ( "FBROW-" , "" );
1443 if ( child
. hasClassName ( 'Selected' )) {
1450 getSelectedFeeds : function () {
1451 var list
= $$( "#browseFeedList li.Selected" );
1452 var selected
= new Array ();
1454 list
. each ( function ( child
) {
1455 var title
= child
. getElementsBySelector ( "span.fb_feedTitle" )[ 0 ]. innerHTML
;
1456 var url
= child
. getElementsBySelector ( "a.fb_feedUrl" )[ 0 ]. href
;
1458 selected
. push ([ title
, url
]);
1465 subscribe : function () {
1466 var mode
= this . attr ( 'value' ). mode
;
1470 selected
= this . getSelectedFeeds ();
1472 selected
= this . getSelectedFeedIds ();
1474 if ( selected
. length
> 0 ) {
1475 dijit
. byId ( "feedBrowserDlg" ). hide ();
1477 notify_progress ( "Loading, please wait..." , true );
1479 // we use dojo.toJson instead of JSON.stringify because
1480 // it somehow escapes everything TWICE, at least in Chrome 9
1482 var query
= "?op=rpc&subop=massSubscribe&payload=" +
1483 param_escape ( dojo
. toJson ( selected
)) + "&mode=" + param_escape ( mode
);
1487 new Ajax
. Request ( "backend.php" , {
1489 onComplete : function ( transport
) {
1495 alert ( __ ( "No feeds are selected." ));
1499 update : function () {
1500 var query
= dojo
. objectToQuery ( dialog
. attr ( 'value' ));
1502 Element
. show ( 'feed_browser_spinner' );
1504 new Ajax
. Request ( "backend.php" , {
1506 onComplete : function ( transport
) {
1509 Element
. hide ( 'feed_browser_spinner' );
1511 var c
= $( "browseFeedList" );
1513 var reply
= JSON
. parse ( transport
. responseText
);
1515 var r
= reply
[ 'content' ];
1516 var mode
= reply
[ 'mode' ];
1522 dojo
. parser
. parse ( "browseFeedList" );
1525 Element
. show ( dijit
. byId ( 'feed_archive_remove' ). domNode
);
1527 Element
. hide ( dijit
. byId ( 'feed_archive_remove' ). domNode
);
1532 removeFromArchive : function () {
1533 var selected
= this . getSelectedFeeds ();
1535 if ( selected
. length
> 0 ) {
1537 var pr
= __ ( "Remove selected feeds from the archive? Feeds with stored articles will not be removed." );
1540 Element
. show ( 'feed_browser_spinner' );
1542 var query
= "?op=rpc&subop=remarchived&ids=" +
1543 param_escape ( selected
. toString ());;
1545 new Ajax
. Request ( "backend.php" , {
1547 onComplete : function ( transport
) {
1553 execute : function () {
1554 if ( this . validate ()) {
1563 exception_error ( "editFeed" , e
);
1567 function showFeedsWithErrors () {
1569 var query
= "backend.php?op=dlg&id=feedsWithErrors" ;
1571 if ( dijit
. byId ( "errorFeedsDlg" ))
1572 dijit
. byId ( "errorFeedsDlg" ). destroyRecursive ();
1574 dialog
= new dijit
. Dialog ({
1575 id
: "errorFeedsDlg" ,
1576 title
: __ ( "Feeds with update errors" ),
1577 style
: "width: 600px" ,
1578 getSelectedFeeds : function () {
1579 return getSelectedTableRowIds ( "prefErrorFeedList" );
1581 removeSelected : function () {
1582 var sel_rows
= this . getSelectedFeeds ();
1584 console
. log ( sel_rows
);
1586 if ( sel_rows
. length
> 0 ) {
1587 var ok
= confirm ( __ ( "Remove selected feeds?" ));
1590 notify_progress ( "Removing selected feeds..." , true );
1592 var query
= "?op=pref-feeds&subop=remove&ids=" +
1593 param_escape ( sel_rows
. toString ());
1595 new Ajax
. Request ( "backend.php" , {
1597 onComplete : function ( transport
) {
1605 alert ( __ ( "No feeds are selected." ));
1608 execute : function () {
1609 if ( this . validate ()) {
1617 exception_error ( "showFeedsWithErrors" , e
);
1622 /* new support functions for SelectByTag */
1624 function get_all_tags ( selObj
){
1626 if ( ! selObj
) return "" ;
1629 var len
= selObj
. options
. length
;
1631 for ( var i
= 0 ; i
< len
; i
++){
1632 if ( selObj
. options
[ i
]. selected
) {
1633 result
+= selObj
[ i
]. value
+ "%2C" ; // is really a comma
1637 if ( result
. length
> 0 ){
1638 result
= result
. substr ( 0 , result
. length
- 3 ); // remove trailing %2C
1644 exception_error ( "get_all_tags" , e
);
1648 function get_radio_checked ( radioObj
) {
1650 if (! radioObj
) return "" ;
1652 var len
= radioObj
. length
;
1654 if ( len
== undefined ){
1655 if ( radioObj
. checked
){
1656 return ( radioObj
. value
);
1662 for ( var i
= 0 ; i
< len
; i
++ ){
1663 if ( radioObj
[ i
]. checked
){
1664 return ( radioObj
[ i
]. value
);
1669 exception_error ( "get_radio_checked" , e
);