]>
git.wh0rd.org - tt-rss.git/blob - js/functions.js
1 var notify_silent
= false ;
2 var loading_progress
= 0 ;
3 var sanity_check_done
= false ;
6 Ajax
. Base
. prototype . initialize
= Ajax
. Base
. prototype . initialize
. wrap (
7 function ( callOriginal
, options
) {
9 if ( getInitParam ( "csrf_token" ) != undefined ) {
10 Object
. extend ( options
, options
|| { });
12 if ( Object
. isString ( options
. parameters
))
13 options
. parameters
= options
. parameters
. toQueryParams ();
14 else if ( Object
. isHash ( options
. parameters
))
15 options
. parameters
= options
. parameters
. toObject ();
17 options
. parameters
[ "csrf_token" ] = getInitParam ( "csrf_token" );
20 return callOriginal ( options
);
24 /* add method to remove element from array */
26 Array
. prototype . remove = function ( s
) {
27 for ( var i
= 0 ; i
< this . length
; i
++) {
28 if ( s
== this [ i
]) this . splice ( i
, 1 );
32 /* create console.log if it doesn't exist */
34 if (! window
. console
) console
= {};
35 console
. log
= console
. log
|| function ( msg
) { };
36 console
. warn
= console
. warn
|| function ( msg
) { };
37 console
. error
= console
. error
|| function ( msg
) { };
39 function exception_error ( location
, e
, ext_info
) {
40 var msg
= format_exception_error ( location
, e
);
42 if (! ext_info
) ext_info
= false ;
47 if ( ext_info
. responseText
) {
48 ext_info
= ext_info
. responseText
;
52 var content
= "<div class= \" fatalError \" >" +
53 "<pre>" + msg
+ "</pre>" ;
55 content
+= "<form name= \" exceptionForm \" id= \" exceptionForm \" target= \" _blank \" " +
56 "action= \" http://tt-rss.org/report.php \" method= \" POST \" >" ;
58 content
+= "<textarea style= \" display : none \" name= \" message \" >" + msg
+ "</textarea>" ;
59 content
+= "<textarea style= \" display : none \" name= \" params \" >N/A</textarea>" ;
62 content
+= "<div><b>Additional information:</b></div>" +
63 "<textarea name= \" xinfo \" readonly= \" 1 \" >" + ext_info
+ "</textarea>" ;
66 content
+= "<div><b>Stack trace:</b></div>" +
67 "<textarea name= \" stack \" readonly= \" 1 \" >" + e
. stack
+ "</textarea>" ;
73 content
+= "<div class='dlgButtons'>" ;
75 content
+= "<button dojoType= \" dijit.form.Button \" " +
76 "onclick= \" dijit.byId('exceptionDlg').report() \" >" +
77 __ ( 'Report to tt-rss.org' ) + "</button> " ;
78 content
+= "<button dojoType= \" dijit.form.Button \" " +
79 "onclick= \" dijit.byId('exceptionDlg').hide() \" >" +
80 __ ( 'Close' ) + "</button>" ;
83 if ( dijit
. byId ( "exceptionDlg" ))
84 dijit
. byId ( "exceptionDlg" ). destroyRecursive ();
86 var dialog
= new dijit
. Dialog ({
88 title
: "Unhandled exception" ,
89 style
: "width: 600px" ,
91 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." ))) {
93 document
. forms
[ 'exceptionForm' ]. params
. value
= $ H ({
94 browserName
: navigator
. appName
,
95 browserVersion
: navigator
. appVersion
,
96 browserPlatform
: navigator
. platform
,
97 browserCookies
: navigator
. cookieEnabled
,
100 document
. forms
[ 'exceptionForm' ]. submit ();
114 function format_exception_error ( location
, e
) {
118 var base_fname
= e
. fileName
. substring ( e
. fileName
. lastIndexOf ( "/" ) + 1 );
120 msg
= "Exception: " + e
. name
+ ", " + e
. message
+
121 " \n Function: " + location
+ "()" +
122 " \n Location: " + base_fname
+ ":" + e
. lineNumber
;
124 } else if ( e
. description
) {
125 msg
= "Exception: " + e
. description
+ " \n Function: " + location
+ "()" ;
127 msg
= "Exception: " + e
+ " \n Function: " + location
+ "()" ;
130 console
. error ( "EXCEPTION: " + msg
);
135 function param_escape ( arg
) {
136 if ( typeof encodeURIComponent
!= 'undefined' )
137 return encodeURIComponent ( arg
);
142 function param_unescape ( arg
) {
143 if ( typeof decodeURIComponent
!= 'undefined' )
144 return decodeURIComponent ( arg
);
146 return unescape ( arg
);
149 var notify_hide_timerid
= false ;
151 function hide_notify () {
154 n
. style
. display
= "none" ;
158 function notify_silent_next () {
159 notify_silent
= true ;
162 function notify_real ( msg
, no_hide
, n_type
) {
165 notify_silent
= false ;
170 var nb
= $( "notify_body" );
172 if (! n
|| ! nb
) return ;
174 if ( notify_hide_timerid
) {
175 window
. clearTimeout ( notify_hide_timerid
);
179 if ( n
. style
. display
== "block" ) {
180 notify_hide_timerid
= window
. setTimeout ( "hide_notify()" , 0 );
184 n
. style
. display
= "block" ;
196 if ( typeof __
!= 'undefined' ) {
201 n
. className
= "notify" ;
202 } else if ( n_type
== 2 ) {
203 n
. className
= "notifyProgress" ;
204 msg
= "<img src='" + getInitParam ( "sign_progress" )+ "'> " + msg
;
205 } else if ( n_type
== 3 ) {
206 n
. className
= "notifyError" ;
207 msg
= "<img src='" + getInitParam ( "sign_excl" )+ "'> " + msg
;
208 } else if ( n_type
== 4 ) {
209 n
. className
= "notifyInfo" ;
210 msg
= "<img src='" + getInitParam ( "sign_info" )+ "'> " + msg
;
213 // msg = "<img src='images/live_com_loading.gif'> " + msg;
218 notify_hide_timerid
= window
. setTimeout ( "hide_notify()" , 3000 );
222 function notify ( msg
, no_hide
) {
223 notify_real ( msg
, no_hide
, 1 );
226 function notify_progress ( msg
, no_hide
) {
227 notify_real ( msg
, no_hide
, 2 );
230 function notify_error ( msg
, no_hide
) {
231 notify_real ( msg
, no_hide
, 3 );
235 function notify_info ( msg
, no_hide
) {
236 notify_real ( msg
, no_hide
, 4 );
239 function setCookie ( name
, value
, lifetime
, path
, domain
, secure
) {
245 d
. setTime ( d
. getTime () + ( lifetime
* 1000 ));
248 console
. log ( "setCookie: " + name
+ " => " + value
+ ": " + d
);
250 int_setCookie ( name
, value
, d
, path
, domain
, secure
);
254 function int_setCookie ( name
, value
, expires
, path
, domain
, secure
) {
255 document
. cookie
= name
+ "=" + escape ( value
) +
256 (( expires
) ? "; expires=" + expires
. toGMTString () : "" ) +
257 (( path
) ? "; path=" + path
: "" ) +
258 (( domain
) ? "; domain=" + domain
: "" ) +
259 (( secure
) ? "; secure" : "" );
262 function delCookie ( name
, path
, domain
) {
263 if ( getCookie ( name
)) {
264 document
. cookie
= name
+ "=" +
265 (( path
) ? ";path=" + path
: "" ) +
266 (( domain
) ? ";domain=" + domain
: "" ) +
267 ";expires=Thu, 01-Jan-1970 00:00:01 GMT" ;
272 function getCookie ( name
) {
274 var dc
= document
. cookie
;
275 var prefix
= name
+ "=" ;
276 var begin
= dc
. indexOf ( "; " + prefix
);
278 begin
= dc
. indexOf ( prefix
);
279 if ( begin
!= 0 ) return null ;
284 var end
= document
. cookie
. indexOf ( ";" , begin
);
288 return unescape ( dc
. substring ( begin
+ prefix
. length
, end
));
291 function gotoPreferences () {
292 document
. location
. href
= "prefs.php" ;
295 function gotoLogout () {
296 document
. location
. href
= "backend.php?op=logout" ;
299 function gotoMain () {
300 document
. location
. href
= "index.php" ;
303 /** * @(#)isNumeric.js * * Copyright (c) 2000 by Sundar Dorai-Raj
304 * * @author Sundar Dorai-Raj
305 * * Email: sdoraira@vt.edu
306 * * This program is free software; you can redistribute it and/or
307 * * modify it under the terms of the GNU General Public License
308 * * as published by the Free Software Foundation; either version 2
309 * * of the License, or (at your option) any later version,
310 * * provided that any use properly credits the author.
311 * * This program is distributed in the hope that it will be useful,
312 * * but WITHOUT ANY WARRANTY; without even the implied warranty of
313 * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
314 * * GNU General Public License for more details at http://www.gnu.org * * */
316 var numbers
= ".0123456789" ;
317 function isNumeric ( x
) {
318 // is x a String or a character?
320 // remove negative sign
322 for ( var j
= 0 ; j
< x
. length
; j
++) {
323 // call isNumeric recursively for each character
324 number
= isNumeric ( x
. substring ( j
, j
+ 1 ));
325 if (! number
) return number
;
330 // if x is number return true
331 if ( numbers
. indexOf ( x
)>= 0 ) return true ;
337 function toggleSelectRowById ( sender
, id
) {
339 return toggleSelectRow ( sender
, row
);
342 function toggleSelectListRow ( sender
) {
343 var row
= sender
. parentNode
;
344 return toggleSelectRow ( sender
, row
);
347 /* this is for dijit Checkbox */
348 function toggleSelectListRow2 ( sender
) {
349 var row
= sender
. domNode
. parentNode
;
350 return toggleSelectRow ( sender
, row
);
353 /* this is for dijit Checkbox */
354 function toggleSelectRow2 ( sender
, row
) {
356 if (! row
) row
= sender
. domNode
. parentNode
. parentNode
;
358 if ( sender
. checked
&& ! row
. hasClassName ( 'Selected' ))
359 row
. addClassName ( 'Selected' );
361 row
. removeClassName ( 'Selected' );
365 function toggleSelectRow ( sender
, row
) {
367 if (! row
) row
= sender
. parentNode
. parentNode
;
369 if ( sender
. checked
&& ! row
. hasClassName ( 'Selected' ))
370 row
. addClassName ( 'Selected' );
372 row
. removeClassName ( 'Selected' );
375 function checkboxToggleElement ( elem
, id
) {
377 Effect
. Appear ( id
, { duration
: 0.5 });
379 Effect
. Fade ( id
, { duration
: 0.5 });
383 function dropboxSelect ( e
, v
) {
384 for ( var i
= 0 ; i
< e
. length
; i
++) {
385 if ( e
[ i
]. value
== v
) {
392 function getURLParam ( param
){
393 return String ( window
. location
. href
). parseQuery ()[ param
];
396 function closeInfoBox ( cleanup
) {
398 dialog
= dijit
. byId ( "infoBox" );
400 if ( dialog
) dialog
. hide ();
403 //exception_error("closeInfoBox", e);
409 function displayDlg ( id
, param
, callback
) {
411 notify_progress ( "Loading, please wait..." , true );
413 var query
= "?op=dlg&method=" +
414 param_escape ( id
) + "¶m=" + param_escape ( param
);
416 new Ajax
. Request ( "backend.php" , {
418 onComplete : function ( transport
) {
419 infobox_callback2 ( transport
);
420 if ( callback
) callback ( transport
);
426 function infobox_callback2 ( transport
) {
430 if ( dijit
. byId ( "infoBox" )) {
431 dialog
= dijit
. byId ( "infoBox" );
434 //console.log("infobox_callback2");
437 var title
= transport
. responseXML
. getElementsByTagName ( "title" )[ 0 ];
439 title
= title
. firstChild
. nodeValue
;
441 var content
= transport
. responseXML
. getElementsByTagName ( "content" )[ 0 ];
443 content
= content
. firstChild
. nodeValue
;
446 dialog
= new dijit
. Dialog ({
449 style
: "width: 600px" ,
450 onCancel : function () {
453 onExecute : function () {
456 onClose : function () {
461 dialog
. attr ( 'title' , title
);
462 dialog
. attr ( 'content' , content
);
469 exception_error ( "infobox_callback2" , e
);
473 function filterCR ( e
, f
)
478 key
= window
. event
. keyCode
; //IE
480 key
= e
. which
; //firefox
483 if ( typeof f
!= 'undefined' ) {
494 function getInitParam ( key
) {
495 return init_params
[ key
];
498 function setInitParam ( key
, value
) {
499 init_params
[ key
] = value
;
502 function fatalError ( code
, msg
, ext_info
) {
506 window
. location
. href
= "index.php" ;
507 } else if ( code
== 5 ) {
508 window
. location
. href
= "db-updater.php" ;
511 if ( msg
== "" ) msg
= "Unknown error" ;
514 if ( ext_info
. responseText
) {
515 ext_info
= ext_info
. responseText
;
519 if ( ERRORS
&& ERRORS
[ code
] && ! msg
) {
523 var content
= "<div><b>Error code:</b> " + code
+ "</div>" +
524 "<p>" + msg
+ "</p>" ;
527 content
= content
+ "<div><b>Additional information:</b></div>" +
528 "<textarea style='width: 100%' readonly= \" 1 \" >" +
529 ext_info
+ "</textarea>" ;
532 var dialog
= new dijit
. Dialog ({
533 title
: "Fatal error" ,
534 style
: "width: 600px" ,
544 exception_error ( "fatalError" , e
);
548 /* function filterDlgCheckType(sender) {
552 var ftype = sender.value;
554 // if selected filter type is 5 (Date) enable the modifier dropbox
556 Element.show("filterDlg_dateModBox");
557 Element.show("filterDlg_dateChkBox");
559 Element.hide("filterDlg_dateModBox");
560 Element.hide("filterDlg_dateChkBox");
565 exception_error("filterDlgCheckType", e);
570 function filterDlgCheckAction ( sender
) {
574 var action
= sender
. value
;
576 var action_param
= $( "filterDlg_paramBox" );
579 console
. log ( "filterDlgCheckAction: can't find action param box!" );
583 // if selected action supports parameters, enable params field
584 if ( action
== 4 || action
== 6 || action
== 7 ) {
585 new Effect
. Appear ( action_param
, { duration
: 0.5 });
587 Element
. show ( dijit
. byId ( "filterDlg_actionParam" ). domNode
);
588 Element
. hide ( dijit
. byId ( "filterDlg_actionParamLabel" ). domNode
);
590 Element
. show ( dijit
. byId ( "filterDlg_actionParamLabel" ). domNode
);
591 Element
. hide ( dijit
. byId ( "filterDlg_actionParam" ). domNode
);
594 Element
. hide ( action_param
);
598 exception_error ( "filterDlgCheckAction" , e
);
603 function filterDlgCheckDate () {
605 var dialog
= dijit
. byId ( "filterEditDlg" );
607 var reg_exp
= dialog
. attr ( 'value' ). reg_exp
;
609 var query
= "?op=rpc&method=checkDate&date=" + reg_exp
;
611 new Ajax
. Request ( "backend.php" , {
613 onComplete : function ( transport
) {
615 var reply
= JSON
. parse ( transport
. responseText
);
617 if ( reply
[ 'result' ] == true ) {
618 alert ( __ ( "Date syntax appears to be correct:" ) + " " + reply
[ 'date' ]);
621 alert ( __ ( "Date syntax is incorrect." ));
628 exception_error ( "filterDlgCheckDate" , e
);
632 function explainError ( code
) {
633 return displayDlg ( "explainError" , code
);
636 function loading_set_progress ( p
) {
638 loading_progress
+= p
;
640 if ( dijit
. byId ( "loading_bar" ))
641 dijit
. byId ( "loading_bar" ). update ({ progress
: loading_progress
});
643 if ( loading_progress
>= 90 )
647 exception_error ( "loading_set_progress" , e
);
651 function remove_splash () {
653 if ( Element
. visible ( "overlay" )) {
654 console
. log ( "about to remove splash, OMG!" );
655 Element
. hide ( "overlay" );
656 console
. log ( "removed splash!" );
660 function transport_error_check ( transport
) {
662 if ( transport
. responseXML
) {
663 var error
= transport
. responseXML
. getElementsByTagName ( "error" )[ 0 ];
666 var code
= error
. getAttribute ( "error-code" );
667 var msg
= error
. getAttribute ( "error-msg" );
669 fatalError ( code
, msg
);
675 exception_error ( "check_for_error_xml" , e
);
680 function strip_tags ( s
) {
681 return s
. replace ( /<\/?[^>]+(>|$)/g , "" );
684 function truncate_string ( s
, length
) {
685 if (! length
) length
= 30 ;
686 var tmp
= s
. substring ( 0 , length
);
687 if ( s
. length
> length
) tmp
+= "…" ;
691 function hotkey_prefix_timeout () {
694 var date
= new Date ();
695 var ts
= Math
. round ( date
. getTime () / 1000 );
697 if ( hotkey_prefix_pressed
&& ts
- hotkey_prefix_pressed
>= 5 ) {
698 console
. log ( "hotkey_prefix seems to be stuck, aborting" );
699 hotkey_prefix_pressed
= false ;
700 hotkey_prefix
= false ;
701 Element
. hide ( 'cmdline' );
704 setTimeout ( "hotkey_prefix_timeout()" , 1000 );
707 exception_error ( "hotkey_prefix_timeout" , e
);
711 function hideAuxDlg () {
713 Element
. hide ( 'auxDlg' );
715 exception_error ( "hideAuxDlg" , e
);
720 function uploadIconHandler ( rc
) {
724 notify_info ( "Upload complete." );
725 if ( inPreferences ()) {
728 setTimeout ( 'updateFeedList(false, false)' , 50 );
732 notify_error ( "Upload failed: icon is too big." );
735 notify_error ( "Upload failed." );
740 exception_error ( "uploadIconHandler" , e
);
744 function removeFeedIcon ( id
) {
748 if ( confirm ( __ ( "Remove stored feed icon?" ))) {
749 var query
= "backend.php?op=pref-feeds&method=removeicon&feed_id=" + param_escape ( id
);
753 notify_progress ( "Removing feed icon..." , true );
755 new Ajax
. Request ( "backend.php" , {
757 onComplete : function ( transport
) {
758 notify_info ( "Feed icon removed." );
759 if ( inPreferences ()) {
762 setTimeout ( 'updateFeedList(false, false)' , 50 );
769 exception_error ( "removeFeedIcon" , e
);
773 function uploadFeedIcon () {
777 var file
= $( "icon_file" );
779 if ( file
. value
. length
== 0 ) {
780 alert ( __ ( "Please select an image file to upload." ));
782 if ( confirm ( __ ( "Upload new icon for this feed?" ))) {
783 notify_progress ( "Uploading, please wait..." , true );
791 exception_error ( "uploadFeedIcon" , e
);
795 function addLabel ( select
, callback
) {
799 var caption
= prompt ( __ ( "Please enter label caption:" ), "" );
801 if ( caption
!= undefined ) {
804 alert ( __ ( "Can't create label: missing caption." ));
808 var query
= "?op=pref-labels&method=add&caption=" +
809 param_escape ( caption
);
812 query
+= "&output=select" ;
814 notify_progress ( "Loading, please wait..." , true );
816 if ( inPreferences () && ! select
) active_tab
= "labelConfig" ;
818 new Ajax
. Request ( "backend.php" , {
820 onComplete : function ( transport
) {
823 } else if ( inPreferences ()) {
833 exception_error ( "addLabel" , e
);
837 function quickAddFeed () {
839 var query
= "backend.php?op=dlg&method=quickAddFeed" ;
841 // overlapping widgets
842 if ( dijit
. byId ( "batchSubDlg" )) dijit
. byId ( "batchSubDlg" ). destroyRecursive ();
843 if ( dijit
. byId ( "feedAddDlg" )) dijit
. byId ( "feedAddDlg" ). destroyRecursive ();
845 var dialog
= new dijit
. Dialog ({
847 title
: __ ( "Subscribe to Feed" ),
848 style
: "width: 600px" ,
849 execute : function () {
850 if ( this . validate ()) {
851 console
. log ( dojo
. objectToQuery ( this . attr ( 'value' )));
853 var feed_url
= this . attr ( 'value' ). feed
;
855 Element
. show ( "feed_add_spinner" );
857 new Ajax
. Request ( "backend.php" , {
858 parameters
: dojo
. objectToQuery ( this . attr ( 'value' )),
859 onComplete : function ( transport
) {
862 var reply
= JSON
. parse ( transport
. responseText
);
864 var rc
= reply
[ 'result' ];
867 Element
. hide ( "feed_add_spinner" );
869 console
. log ( "GOT RC: " + rc
);
871 switch ( parseInt ( rc
[ 'code' ])) {
874 notify_info ( __ ( "Subscribed to %s" ). replace ( "%s" , feed_url
));
879 alert ( __ ( "Specified URL seems to be invalid." ));
882 alert ( __ ( "Specified URL doesn't seem to contain any feeds." ));
885 /* notify_progress("Searching for feed urls...", true);
887 new Ajax.Request("backend.php", {
888 parameters: 'op=rpc&method=extractfeedurls&url=' + param_escape(feed_url),
889 onComplete: function(transport, dialog, feed_url) {
893 var reply = JSON.parse(transport.responseText);
895 var feeds = reply['urls'];
897 console.log(transport.responseText);
899 var select = dijit.byId("feedDlg_feedContainerSelect");
901 while (select.getOptions().length > 0)
902 select.removeOption(0);
905 for (var feedUrl in feeds) {
906 select.addOption({value: feedUrl, label: feeds[feedUrl]});
910 // if (count > 5) count = 5;
911 // select.size = count;
913 Effect.Appear('feedDlg_feedsContainer', {duration : 0.5});
920 var select
= dijit
. byId ( "feedDlg_feedContainerSelect" );
922 while ( select
. getOptions (). length
> 0 )
923 select
. removeOption ( 0 );
926 for ( var feedUrl
in feeds
) {
927 select
. addOption ({ value
: feedUrl
, label
: feeds
[ feedUrl
]});
931 Effect
. Appear ( 'feedDlg_feedsContainer' , { duration
: 0.5 });
935 alert ( __ ( "Couldn't download the specified URL: %s" ).
936 replace ( "%s" , rc
[ 'message' ]));
939 alert ( __ ( "You are already subscribed to this feed." ));
944 exception_error ( "subscribeToFeed" , e
, transport
);
955 exception_error ( "quickAddFeed" , e
);
959 function createNewRuleElement ( parentNode
, replaceNode
) {
961 var form
= document
. forms
[ "filter_new_rule_form" ];
963 var query
= "backend.php?op=pref-filters&method=printrulename&rule=" +
964 param_escape ( dojo
. formToJson ( form
));
968 new Ajax
. Request ( "backend.php" , {
970 onComplete : function ( transport
) {
972 var li
= dojo
. create ( "li" );
974 var cb
= dojo
. create ( "input" , { type
: "checkbox" }, li
);
976 new dijit
. form
. CheckBox ({
977 onChange : function () {
978 toggleSelectListRow2 ( this ) },
981 dojo
. create ( "input" , { type
: "hidden" ,
983 value
: dojo
. formToJson ( form
) }, li
);
985 dojo
. create ( "span" , {
986 onclick : function () {
987 dijit
. byId ( 'filterEditDlg' ). editRule ( this );
989 innerHTML
: transport
. responseText
}, li
);
992 parentNode
. replaceChild ( li
, replaceNode
);
994 parentNode
. appendChild ( li
);
997 exception_error ( "createNewRuleElement" , e
);
1001 exception_error ( "createNewRuleElement" , e
);
1005 function createNewActionElement ( parentNode
, replaceNode
) {
1007 var form
= document
. forms
[ "filter_new_action_form" ];
1009 if ( form
. action_id
. value
== 7 ) {
1010 form
. action_param
. value
= form
. action_param_label
. value
;
1013 var query
= "backend.php?op=pref-filters&method=printactionname&action=" +
1014 param_escape ( dojo
. formToJson ( form
));
1018 new Ajax
. Request ( "backend.php" , {
1020 onComplete : function ( transport
) {
1022 var li
= dojo
. create ( "li" );
1024 var cb
= dojo
. create ( "input" , { type
: "checkbox" }, li
);
1026 new dijit
. form
. CheckBox ({
1027 onChange : function () {
1028 toggleSelectListRow2 ( this ) },
1031 dojo
. create ( "input" , { type
: "hidden" ,
1033 value
: dojo
. formToJson ( form
) }, li
);
1035 dojo
. create ( "span" , {
1036 onclick : function () {
1037 dijit
. byId ( 'filterEditDlg' ). editAction ( this );
1039 innerHTML
: transport
. responseText
}, li
);
1042 parentNode
. replaceChild ( li
, replaceNode
);
1044 parentNode
. appendChild ( li
);
1048 exception_error ( "createNewActionElement" , e
);
1052 exception_error ( "createNewActionElement" , e
);
1057 function addFilterRule ( replaceNode
, ruleStr
) {
1059 if ( dijit
. byId ( "filterNewRuleDlg" ))
1060 dijit
. byId ( "filterNewRuleDlg" ). destroyRecursive ();
1062 var query
= "backend.php?op=pref-filters&method=newrule&rule=" +
1063 param_escape ( ruleStr
);
1065 var rule_dlg
= new dijit
. Dialog ({
1066 id
: "filterNewRuleDlg" ,
1067 title
: ruleStr
? __ ( "Edit rule" ) : __ ( "Add rule" ),
1068 style
: "width: 600px" ,
1069 execute : function () {
1070 if ( this . validate ()) {
1071 createNewRuleElement ($( "filterDlg_Matches" ), replaceNode
);
1079 exception_error ( "addFilterRule" , e
);
1083 function addFilterAction ( replaceNode
, actionStr
) {
1085 if ( dijit
. byId ( "filterNewActionDlg" ))
1086 dijit
. byId ( "filterNewActionDlg" ). destroyRecursive ();
1088 var query
= "backend.php?op=pref-filters&method=newaction&action=" +
1089 param_escape ( actionStr
);
1091 var rule_dlg
= new dijit
. Dialog ({
1092 id
: "filterNewActionDlg" ,
1093 title
: actionStr
? __ ( "Edit action" ) : __ ( "Add action" ),
1094 style
: "width: 600px" ,
1095 execute : function () {
1096 if ( this . validate ()) {
1097 createNewActionElement ($( "filterDlg_Actions" ), replaceNode
);
1105 exception_error ( "addFilterAction" , e
);
1109 function quickAddFilter () {
1112 if (! inPreferences ()) {
1113 query
= "backend.php?op=pref-filters&method=newfilter&feed=" +
1114 param_escape ( getActiveFeedId ()) + "&is_cat=" +
1115 param_escape ( activeFeedIsCat ());
1117 query
= "backend.php?op=pref-filters&method=newfilter" ;
1122 if ( dijit
. byId ( "feedEditDlg" ))
1123 dijit
. byId ( "feedEditDlg" ). destroyRecursive ();
1125 if ( dijit
. byId ( "filterEditDlg" ))
1126 dijit
. byId ( "filterEditDlg" ). destroyRecursive ();
1128 dialog
= new dijit
. Dialog ({
1129 id
: "filterEditDlg" ,
1130 title
: __ ( "Create Filter" ),
1131 style
: "width: 600px" ,
1133 var query
= "backend.php?" + dojo
. formToQuery ( "filter_new_form" ) + "&savemode=test" ;
1135 if ( dijit
. byId ( "filterTestDlg" ))
1136 dijit
. byId ( "filterTestDlg" ). destroyRecursive ();
1138 var test_dlg
= new dijit
. Dialog ({
1139 id
: "filterTestDlg" ,
1140 title
: "Test Filter" ,
1141 style
: "width: 600px" ,
1146 selectRules : function ( select
) {
1147 $$( "#filterDlg_Matches input[type=checkbox]" ). each ( function ( e
) {
1150 e
. parentNode
. addClassName ( "Selected" );
1152 e
. parentNode
. removeClassName ( "Selected" );
1155 selectActions : function ( select
) {
1156 $$( "#filterDlg_Actions input[type=checkbox]" ). each ( function ( e
) {
1160 e
. parentNode
. addClassName ( "Selected" );
1162 e
. parentNode
. removeClassName ( "Selected" );
1166 editRule : function ( e
) {
1167 var li
= e
. parentNode
;
1168 var rule
= li
. getElementsByTagName ( "INPUT" )[ 1 ]. value
;
1169 addFilterRule ( li
, rule
);
1171 editAction : function ( e
) {
1172 var li
= e
. parentNode
;
1173 var action
= li
. getElementsByTagName ( "INPUT" )[ 1 ]. value
;
1174 addFilterAction ( li
, action
);
1176 addAction : function () { addFilterAction (); },
1177 addRule : function () { addFilterRule (); },
1178 deleteAction : function () {
1179 $$( "#filterDlg_Actions li.[class*=Selected]" ). each ( function ( e
) { e
. parentNode
. removeChild ( e
) });
1181 deleteRule : function () {
1182 $$( "#filterDlg_Matches li.[class*=Selected]" ). each ( function ( e
) { e
. parentNode
. removeChild ( e
) });
1184 execute : function () {
1185 if ( this . validate ()) {
1187 var query
= dojo
. formToQuery ( "filter_new_form" );
1191 new Ajax
. Request ( "backend.php" , {
1193 onComplete : function ( transport
) {
1194 if ( inPreferences ()) {
1204 if (! inPreferences ()) {
1205 var lh
= dojo
. connect ( dialog
, "onLoad" , function (){
1206 dojo
. disconnect ( lh
);
1208 var title
= $( "PTITLE-FULL-" + active_post_id
);
1210 if ( title
|| getActiveFeedId () || activeFeedIsCat ()) {
1211 if ( title
) title
= title
. innerHTML
;
1213 console
. log ( title
+ " " + getActiveFeedId ());
1215 var feed_id
= activeFeedIsCat () ? 'CAT:' + parseInt ( getActiveFeedId ()) :
1218 var rule
= { reg_exp
: title
, feed_id
: feed_id
, filter_type
: 1 };
1220 addFilterRule ( null , dojo
. toJson ( rule
));
1228 exception_error ( "quickAddFilter" , e
);
1232 function resetPubSub ( feed_id
, title
) {
1234 var msg
= __ ( "Reset subscription? Tiny Tiny RSS will try to subscribe to the notification hub again on next feed update." ). replace ( "%s" , title
);
1236 if ( title
== undefined || confirm ( msg
)) {
1237 notify_progress ( "Loading, please wait..." );
1239 var query
= "?op=pref-feeds&quiet=1&method=resetPubSub&ids=" + feed_id
;
1241 new Ajax
. Request ( "backend.php" , {
1243 onComplete : function ( transport
) {
1244 dijit
. byId ( "pubsubReset_Btn" ). attr ( 'disabled' , true );
1245 notify_info ( "Subscription reset." );
1253 function unsubscribeFeed ( feed_id
, title
) {
1255 var msg
= __ ( "Unsubscribe from %s?" ). replace ( "%s" , title
);
1257 if ( title
== undefined || confirm ( msg
)) {
1258 notify_progress ( "Removing feed..." );
1260 var query
= "?op=pref-feeds&quiet=1&method=remove&ids=" + feed_id
;
1262 new Ajax
. Request ( "backend.php" , {
1264 onComplete : function ( transport
) {
1266 if ( dijit
. byId ( "feedEditDlg" )) dijit
. byId ( "feedEditDlg" ). hide ();
1268 if ( inPreferences ()) {
1271 if ( feed_id
== getActiveFeedId ())
1272 setTimeout ( "viewfeed(-5)" , 100 );
1282 function backend_sanity_check_callback ( transport
) {
1286 if ( sanity_check_done
) {
1287 fatalError ( 11 , "Sanity check request received twice. This can indicate " +
1288 "presence of Firebug or some other disrupting extension. " +
1289 "Please disable it and try again." );
1293 var reply
= JSON
. parse ( transport
. responseText
);
1296 fatalError ( 3 , "Sanity check: invalid RPC reply" , transport
. responseText
);
1300 var error_code
= reply
[ 'error' ][ 'code' ];
1302 if ( error_code
&& error_code
!= 0 ) {
1303 return fatalError ( error_code
, reply
[ 'error' ][ 'message' ]);
1306 console
. log ( "sanity check ok" );
1308 var params
= reply
[ 'init-params' ];
1311 console
. log ( 'reading init-params...' );
1316 console
. log ( "IP: " + k
+ " => " + v
);
1320 init_params
= params
;
1323 sanity_check_done
= true ;
1325 init_second_stage ();
1328 exception_error ( "backend_sanity_check_callback" , e
, transport
);
1332 /*function has_local_storage() {
1334 return 'sessionStorage' in window && window['sessionStorage'] != null;
1340 function catSelectOnChange ( elem
) {
1342 /* var value = elem[elem.selectedIndex].value;
1343 var def = elem.getAttribute('default');
1345 if (value == "ADD_CAT") {
1348 dropboxSelect(elem, def);
1350 elem.selectedIndex = 0;
1356 exception_error ( "catSelectOnChange" , e
);
1360 function quickAddCat ( elem
) {
1362 var cat
= prompt ( __ ( "Please enter category title:" ));
1366 var query
= "?op=rpc&method=quickAddCat&cat=" + param_escape ( cat
);
1368 notify_progress ( "Loading, please wait..." , true );
1370 new Ajax
. Request ( "backend.php" , {
1372 onComplete : function ( transport
) {
1373 var response
= transport
. responseXML
;
1374 var select
= response
. getElementsByTagName ( "select" )[ 0 ];
1375 var options
= select
. getElementsByTagName ( "option" );
1377 dropbox_replace_options ( elem
, options
);
1386 exception_error ( "quickAddCat" , e
);
1390 function genUrlChangeKey ( feed
, is_cat
) {
1393 var ok
= confirm ( __ ( "Generate new syndication address for this feed?" ));
1397 notify_progress ( "Trying to change address..." , true );
1399 var query
= "?op=rpc&method=regenFeedKey&id=" + param_escape ( feed
) +
1400 "&is_cat=" + param_escape ( is_cat
);
1402 new Ajax
. Request ( "backend.php" , {
1404 onComplete : function ( transport
) {
1405 var reply
= JSON
. parse ( transport
. responseText
);
1406 var new_link
= reply
. link
;
1408 var e
= $( 'gen_feed_url' );
1412 e
. innerHTML
= e
. innerHTML
. replace ( /\&key=.*$/ ,
1413 "&key=" + new_link
);
1415 e
. href
= e
. href
. replace ( /\&key=.*$/ ,
1416 "&key=" + new_link
);
1418 new Effect
. Highlight ( e
);
1423 notify_error ( "Could not change feed URL." );
1428 exception_error ( "genUrlChangeKey" , e
);
1433 function labelSelectOnChange ( elem
) {
1435 /* var value = elem[elem.selectedIndex].value;
1436 var def = elem.getAttribute('default');
1438 if (value == "ADD_LABEL") {
1441 dropboxSelect(elem, def);
1443 elem.selectedIndex = 0;
1445 addLabel(elem, function(transport) {
1449 var response = transport.responseXML;
1450 var select = response.getElementsByTagName("select")[0];
1451 var options = select.getElementsByTagName("option");
1453 dropbox_replace_options(elem, options);
1457 exception_error("addLabel", e);
1463 exception_error ( "labelSelectOnChange" , e
);
1467 function dropbox_replace_options ( elem
, options
) {
1470 while ( elem
. hasChildNodes ())
1471 elem
. removeChild ( elem
. firstChild
);
1475 for ( var i
= 0 ; i
< options
. length
; i
++) {
1476 var text
= options
[ i
]. firstChild
. nodeValue
;
1477 var value
= options
[ i
]. getAttribute ( "value" );
1479 if ( value
== undefined ) value
= text
;
1481 var issel
= options
[ i
]. getAttribute ( "selected" ) == "1" ;
1483 var option
= new Option ( text
, value
, issel
);
1485 if ( options
[ i
]. getAttribute ( "disabled" ))
1486 option
. setAttribute ( "disabled" , true );
1488 elem
. insert ( option
);
1490 if ( issel
) sel_idx
= i
;
1493 // Chrome doesn't seem to just select stuff when you pass new Option(x, y, true)
1494 if ( sel_idx
>= 0 ) elem
. selectedIndex
= sel_idx
;
1497 exception_error ( "dropbox_replace_options" , e
);
1501 // mode = all, none, invert
1502 function selectTableRows ( id
, mode
) {
1504 var rows
= $( id
). rows
;
1506 for ( var i
= 0 ; i
< rows
. length
; i
++) {
1511 if ( row
. id
&& row
. className
) {
1512 var bare_id
= row
. id
. replace ( /^[A-Z]*?-/ , "" );
1513 var inputs
= rows
[ i
]. getElementsByTagName ( "input" );
1515 for ( var j
= 0 ; j
< inputs
. length
; j
++) {
1516 var input
= inputs
[ j
];
1518 if ( input
. getAttribute ( "type" ) == "checkbox" &&
1519 input
. id
. match ( bare_id
)) {
1522 dcb
= dijit
. getEnclosingWidget ( cb
);
1528 var issel
= row
. hasClassName ( "Selected" );
1530 if ( mode
== "all" && ! issel
) {
1531 row
. addClassName ( "Selected" );
1533 if ( dcb
) dcb
. set ( "checked" , true );
1534 } else if ( mode
== "none" && issel
) {
1535 row
. removeClassName ( "Selected" );
1537 if ( dcb
) dcb
. set ( "checked" , false );
1539 } else if ( mode
== "invert" ) {
1542 row
. removeClassName ( "Selected" );
1544 if ( dcb
) dcb
. set ( "checked" , false );
1546 row
. addClassName ( "Selected" );
1548 if ( dcb
) dcb
. set ( "checked" , true );
1556 exception_error ( "selectTableRows" , e
);
1561 function getSelectedTableRowIds ( id
) {
1565 var elem_rows
= $( id
). rows
;
1567 for ( var i
= 0 ; i
< elem_rows
. length
; i
++) {
1568 if ( elem_rows
[ i
]. hasClassName ( "Selected" )) {
1569 var bare_id
= elem_rows
[ i
]. id
. replace ( /^[A-Z]*?-/ , "" );
1575 exception_error ( "getSelectedTableRowIds" , e
);
1581 function editFeed ( feed
, event
) {
1584 return alert ( __ ( "You can't edit this kind of feed." ));
1586 var query
= "backend.php?op=pref-feeds&method=editfeed&id=" +
1591 if ( dijit
. byId ( "filterEditDlg" ))
1592 dijit
. byId ( "filterEditDlg" ). destroyRecursive ();
1594 if ( dijit
. byId ( "feedEditDlg" ))
1595 dijit
. byId ( "feedEditDlg" ). destroyRecursive ();
1597 dialog
= new dijit
. Dialog ({
1599 title
: __ ( "Edit Feed" ),
1600 style
: "width: 600px" ,
1601 execute : function () {
1602 if ( this . validate ()) {
1603 // console.log(dojo.objectToQuery(this.attr('value')));
1605 notify_progress ( "Saving data..." , true );
1607 new Ajax
. Request ( "backend.php" , {
1608 parameters
: dojo
. objectToQuery ( dialog
. attr ( 'value' )),
1609 onComplete : function ( transport
) {
1621 exception_error ( "editFeed" , e
);
1625 function feedBrowser () {
1627 var query
= "backend.php?op=dlg&method=feedBrowser" ;
1629 if ( dijit
. byId ( "feedAddDlg" ))
1630 dijit
. byId ( "feedAddDlg" ). hide ();
1632 if ( dijit
. byId ( "feedBrowserDlg" ))
1633 dijit
. byId ( "feedBrowserDlg" ). destroyRecursive ();
1635 var dialog
= new dijit
. Dialog ({
1636 id
: "feedBrowserDlg" ,
1637 title
: __ ( "More Feeds" ),
1638 style
: "width: 600px" ,
1639 getSelectedFeedIds : function () {
1640 var list
= $$( "#browseFeedList li[id*=FBROW]" );
1641 var selected
= new Array ();
1643 list
. each ( function ( child
) {
1644 var id
= child
. id
. replace ( "FBROW-" , "" );
1646 if ( child
. hasClassName ( 'Selected' )) {
1653 getSelectedFeeds : function () {
1654 var list
= $$( "#browseFeedList li.Selected" );
1655 var selected
= new Array ();
1657 list
. each ( function ( child
) {
1658 var title
= child
. getElementsBySelector ( "span.fb_feedTitle" )[ 0 ]. innerHTML
;
1659 var url
= child
. getElementsBySelector ( "a.fb_feedUrl" )[ 0 ]. href
;
1661 selected
. push ([ title
, url
]);
1668 subscribe : function () {
1669 var mode
= this . attr ( 'value' ). mode
;
1673 selected
= this . getSelectedFeeds ();
1675 selected
= this . getSelectedFeedIds ();
1677 if ( selected
. length
> 0 ) {
1678 dijit
. byId ( "feedBrowserDlg" ). hide ();
1680 notify_progress ( "Loading, please wait..." , true );
1682 // we use dojo.toJson instead of JSON.stringify because
1683 // it somehow escapes everything TWICE, at least in Chrome 9
1685 var query
= "?op=rpc&method=massSubscribe&payload=" +
1686 param_escape ( dojo
. toJson ( selected
)) + "&mode=" + param_escape ( mode
);
1690 new Ajax
. Request ( "backend.php" , {
1692 onComplete : function ( transport
) {
1698 alert ( __ ( "No feeds are selected." ));
1702 update : function () {
1703 var query
= dojo
. objectToQuery ( dialog
. attr ( 'value' ));
1705 Element
. show ( 'feed_browser_spinner' );
1707 new Ajax
. Request ( "backend.php" , {
1709 onComplete : function ( transport
) {
1712 Element
. hide ( 'feed_browser_spinner' );
1714 var c
= $( "browseFeedList" );
1716 var reply
= JSON
. parse ( transport
. responseText
);
1718 var r
= reply
[ 'content' ];
1719 var mode
= reply
[ 'mode' ];
1725 dojo
. parser
. parse ( "browseFeedList" );
1728 Element
. show ( dijit
. byId ( 'feed_archive_remove' ). domNode
);
1730 Element
. hide ( dijit
. byId ( 'feed_archive_remove' ). domNode
);
1735 removeFromArchive : function () {
1736 var selected
= this . getSelectedFeeds ();
1738 if ( selected
. length
> 0 ) {
1740 var pr
= __ ( "Remove selected feeds from the archive? Feeds with stored articles will not be removed." );
1743 Element
. show ( 'feed_browser_spinner' );
1745 var query
= "?op=rpc&method=remarchived&ids=" +
1746 param_escape ( selected
. toString ());;
1748 new Ajax
. Request ( "backend.php" , {
1750 onComplete : function ( transport
) {
1756 execute : function () {
1757 if ( this . validate ()) {
1766 exception_error ( "editFeed" , e
);
1770 function showFeedsWithErrors () {
1772 var query
= "backend.php?op=pref-feeds&method=feedsWithErrors" ;
1774 if ( dijit
. byId ( "errorFeedsDlg" ))
1775 dijit
. byId ( "errorFeedsDlg" ). destroyRecursive ();
1777 dialog
= new dijit
. Dialog ({
1778 id
: "errorFeedsDlg" ,
1779 title
: __ ( "Feeds with update errors" ),
1780 style
: "width: 600px" ,
1781 getSelectedFeeds : function () {
1782 return getSelectedTableRowIds ( "prefErrorFeedList" );
1784 removeSelected : function () {
1785 var sel_rows
= this . getSelectedFeeds ();
1787 console
. log ( sel_rows
);
1789 if ( sel_rows
. length
> 0 ) {
1790 var ok
= confirm ( __ ( "Remove selected feeds?" ));
1793 notify_progress ( "Removing selected feeds..." , true );
1795 var query
= "?op=pref-feeds&method=remove&ids=" +
1796 param_escape ( sel_rows
. toString ());
1798 new Ajax
. Request ( "backend.php" , {
1800 onComplete : function ( transport
) {
1808 alert ( __ ( "No feeds are selected." ));
1811 execute : function () {
1812 if ( this . validate ()) {
1820 exception_error ( "showFeedsWithErrors" , e
);
1825 /* new support functions for SelectByTag */
1827 function get_all_tags ( selObj
){
1829 if ( ! selObj
) return "" ;
1832 var len
= selObj
. options
. length
;
1834 for ( var i
= 0 ; i
< len
; i
++){
1835 if ( selObj
. options
[ i
]. selected
) {
1836 result
+= selObj
[ i
]. value
+ "%2C" ; // is really a comma
1840 if ( result
. length
> 0 ){
1841 result
= result
. substr ( 0 , result
. length
- 3 ); // remove trailing %2C
1847 exception_error ( "get_all_tags" , e
);
1851 function get_radio_checked ( radioObj
) {
1853 if (! radioObj
) return "" ;
1855 var len
= radioObj
. length
;
1857 if ( len
== undefined ){
1858 if ( radioObj
. checked
){
1859 return ( radioObj
. value
);
1865 for ( var i
= 0 ; i
< len
; i
++ ){
1866 if ( radioObj
[ i
]. checked
){
1867 return ( radioObj
[ i
]. value
);
1872 exception_error ( "get_radio_checked" , e
);
1877 function get_timestamp () {
1878 var date
= new Date ();
1879 return Math
. round ( date
. getTime () / 1000 );
1882 function helpDialog ( topic
) {
1884 var query
= "backend.php?op=backend&method=help&topic=" + param_escape ( topic
);
1886 if ( dijit
. byId ( "helpDlg" ))
1887 dijit
. byId ( "helpDlg" ). destroyRecursive ();
1889 dialog
= new dijit
. Dialog ({
1892 style
: "width: 600px" ,
1899 exception_error ( "helpDialog" , e
);