]>
git.wh0rd.org - tt-rss.git/blob - js/functions.js
1 var loading_progress
= 0 ;
2 var sanity_check_done
= false ;
4 var _label_base_index
= - 1024 ;
5 var notify_hide_timerid
= false ;
7 Ajax
. Base
. prototype . initialize
= Ajax
. Base
. prototype . initialize
. wrap (
8 function ( callOriginal
, options
) {
10 if ( getInitParam ( "csrf_token" ) != undefined ) {
11 Object
. extend ( options
, options
|| { });
13 if ( Object
. isString ( options
. parameters
))
14 options
. parameters
= options
. parameters
. toQueryParams ();
15 else if ( Object
. isHash ( options
. parameters
))
16 options
. parameters
= options
. parameters
. toObject ();
18 options
. parameters
[ "csrf_token" ] = getInitParam ( "csrf_token" );
21 return callOriginal ( options
);
25 /* add method to remove element from array */
27 Array
. prototype . remove = function ( s
) {
28 for ( var i
= 0 ; i
< this . length
; i
++) {
29 if ( s
== this [ i
]) this . splice ( i
, 1 );
33 /* create console.log if it doesn't exist */
35 if (! window
. console
) console
= {};
36 console
. log
= console
. log
|| function ( msg
) { };
37 console
. warn
= console
. warn
|| function ( msg
) { };
38 console
. error
= console
. error
|| function ( msg
) { };
40 function exception_error ( location
, e
, ext_info
) {
41 var msg
= format_exception_error ( location
, e
);
43 if (! ext_info
) ext_info
= false ;
48 ext_info
= JSON
. stringify ( ext_info
);
51 new Ajax
. Request ( "backend.php" , {
52 parameters
: { op
: "rpc" , method
: "log" , logmsg
: msg
},
53 onComplete : function ( transport
) {
54 console
. log ( transport
. responseText
);
58 console
. log ( "Exception while trying to log the error." );
62 msg
+= "<p>" + __ ( "The error will be reported to the configured log destination." ) +
65 var content
= "<div class= \" fatalError \" >" +
66 "<pre>" + msg
+ "</pre>" ;
68 content
+= "<form name= \" exceptionForm \" id= \" exceptionForm \" target= \" _blank \" " +
69 "action= \" http://tt-rss.org/report.php \" method= \" POST \" >" ;
71 content
+= "<textarea style= \" display : none \" name= \" message \" >" + msg
+ "</textarea>" ;
72 content
+= "<textarea style= \" display : none \" name= \" params \" >N/A</textarea>" ;
75 content
+= "<div><b>Additional information:</b></div>" +
76 "<textarea name= \" xinfo \" readonly= \" 1 \" >" + ext_info
+ "</textarea>" ;
79 content
+= "<div><b>Stack trace:</b></div>" +
80 "<textarea name= \" stack \" readonly= \" 1 \" >" + e
. stack
+ "</textarea>" ;
86 content
+= "<div class='dlgButtons'>" ;
88 content
+= "<button dojoType= \" dijit.form.Button \" " +
89 "onclick= \" dijit.byId('exceptionDlg').report() \" >" +
90 __ ( 'Report to tt-rss.org' ) + "</button> " ;
91 content
+= "<button dojoType= \" dijit.form.Button \" " +
92 "onclick= \" dijit.byId('exceptionDlg').hide() \" >" +
93 __ ( 'Close' ) + "</button>" ;
96 if ( dijit
. byId ( "exceptionDlg" ))
97 dijit
. byId ( "exceptionDlg" ). destroyRecursive ();
99 var dialog
= new dijit
. Dialog ({
101 title
: "Unhandled exception" ,
102 style
: "width: 600px" ,
104 if ( confirm ( __ ( "Are you sure to report this exception to tt-rss.org? The report will include information about your web browser and tt-rss configuration. Your IP will be saved in the database." ))) {
106 document
. forms
[ 'exceptionForm' ]. params
. value
= $ H ({
107 browserName
: navigator
. appName
,
108 browserVersion
: navigator
. appVersion
,
109 browserPlatform
: navigator
. platform
,
110 browserCookies
: navigator
. cookieEnabled
,
111 ttrssVersion
: __ttrss_version
,
112 initParams
: JSON
. stringify ( init_params
),
115 document
. forms
[ 'exceptionForm' ]. submit ();
124 console
. log ( "Exception while trying to report an exception. Oh boy." );
126 console
. log ( "Original exception:" );
129 msg
+= " \n\n Additional exception caught while trying to show the error dialog. \n\n " + format_exception_error ( 'exception_error' , ei
);
132 new Ajax
. Request ( "backend.php" , {
133 parameters
: { op
: "rpc" , method
: "log" , logmsg
: msg
},
134 onComplete : function ( transport
) {
135 console
. log ( transport
. responseText
);
139 console
. log ( "Third exception while trying to log the error! Seriously?" );
143 msg
+= " \n\n The error will be reported to the configured log destination." ;
150 function format_exception_error ( location
, e
) {
154 var base_fname
= e
. fileName
. substring ( e
. fileName
. lastIndexOf ( "/" ) + 1 );
156 msg
= "Exception: " + e
. name
+ ", " + e
. message
+
157 " \n Function: " + location
+ "()" +
158 " \n Location: " + base_fname
+ ":" + e
. lineNumber
;
160 } else if ( e
. description
) {
161 msg
= "Exception: " + e
. description
+ " \n Function: " + location
+ "()" ;
163 msg
= "Exception: " + e
+ " \n Function: " + location
+ "()" ;
166 console
. error ( "EXCEPTION: " + msg
);
171 function param_escape ( arg
) {
172 if ( typeof encodeURIComponent
!= 'undefined' )
173 return encodeURIComponent ( arg
);
178 function param_unescape ( arg
) {
179 if ( typeof decodeURIComponent
!= 'undefined' )
180 return decodeURIComponent ( arg
);
182 return unescape ( arg
);
185 function notify_real ( msg
, no_hide
, n_type
) {
191 if ( notify_hide_timerid
) {
192 window
. clearTimeout ( notify_hide_timerid
);
196 if ( n
. hasClassName ( "visible" )) {
197 notify_hide_timerid
= window
. setTimeout ( function () {
198 n
. removeClassName ( "visible" ) }, 0 );
212 msg
= "<span class= \" msg \" > " + __ ( msg
) + "</span>" ;
215 msg
= "<span><img src= \" " + getInitParam ( "icon_indicator_white" )+ " \" ></span>" + msg
;
217 } else if ( n_type
== 3 ) {
218 msg
= "<span><img src= \" " + getInitParam ( "icon_alert" )+ " \" ></span>" + msg
;
219 } else if ( n_type
== 4 ) {
220 msg
= "<span><img src= \" " + getInitParam ( "icon_information" )+ " \" ></span>" + msg
;
223 msg
+= " <span><img src= \" " + getInitParam ( "icon_cross" )+ " \" class= \" close \" title= \" " +
224 __ ( "Click to close" ) + " \" onclick= \" notify('') \" ></span>" ;
228 window
. setTimeout ( function () {
231 n
. className
= "notify notify_progress visible" ;
232 } else if ( n_type
== 3 ) {
233 n
. className
= "notify notify_error visible" ;
234 msg
= "<span><img src='images/alert.png'></span>" + msg
;
235 } else if ( n_type
== 4 ) {
236 n
. className
= "notify notify_info visible" ;
238 n
. className
= "notify visible" ;
242 notify_hide_timerid
= window
. setTimeout ( function () {
243 n
. removeClassName ( "visible" ) }, 5 * 1000 );
250 function notify ( msg
, no_hide
) {
251 notify_real ( msg
, no_hide
, 1 );
254 function notify_progress ( msg
, no_hide
) {
255 notify_real ( msg
, no_hide
, 2 );
258 function notify_error ( msg
, no_hide
) {
259 notify_real ( msg
, no_hide
, 3 );
263 function notify_info ( msg
, no_hide
) {
264 notify_real ( msg
, no_hide
, 4 );
267 function setCookie ( name
, value
, lifetime
, path
, domain
, secure
) {
273 d
. setTime ( d
. getTime () + ( lifetime
* 1000 ));
276 console
. log ( "setCookie: " + name
+ " => " + value
+ ": " + d
);
278 int_setCookie ( name
, value
, d
, path
, domain
, secure
);
282 function int_setCookie ( name
, value
, expires
, path
, domain
, secure
) {
283 document
. cookie
= name
+ "=" + escape ( value
) +
284 (( expires
) ? "; expires=" + expires
. toGMTString () : "" ) +
285 (( path
) ? "; path=" + path
: "" ) +
286 (( domain
) ? "; domain=" + domain
: "" ) +
287 (( secure
) ? "; secure" : "" );
290 function delCookie ( name
, path
, domain
) {
291 if ( getCookie ( name
)) {
292 document
. cookie
= name
+ "=" +
293 (( path
) ? ";path=" + path
: "" ) +
294 (( domain
) ? ";domain=" + domain
: "" ) +
295 ";expires=Thu, 01-Jan-1970 00:00:01 GMT" ;
300 function getCookie ( name
) {
302 var dc
= document
. cookie
;
303 var prefix
= name
+ "=" ;
304 var begin
= dc
. indexOf ( "; " + prefix
);
306 begin
= dc
. indexOf ( prefix
);
307 if ( begin
!= 0 ) return null ;
312 var end
= document
. cookie
. indexOf ( ";" , begin
);
316 return unescape ( dc
. substring ( begin
+ prefix
. length
, end
));
319 function gotoPreferences () {
320 document
. location
. href
= "prefs.php" ;
323 function gotoLogout () {
324 document
. location
. href
= "backend.php?op=logout" ;
327 function gotoMain () {
328 document
. location
. href
= "index.php" ;
331 /** * @(#)isNumeric.js * * Copyright (c) 2000 by Sundar Dorai-Raj
332 * * @author Sundar Dorai-Raj
333 * * Email: sdoraira@vt.edu
334 * * This program is free software; you can redistribute it and/or
335 * * modify it under the terms of the GNU General Public License
336 * * as published by the Free Software Foundation; either version 2
337 * * of the License, or (at your option) any later version,
338 * * provided that any use properly credits the author.
339 * * This program is distributed in the hope that it will be useful,
340 * * but WITHOUT ANY WARRANTY; without even the implied warranty of
341 * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
342 * * GNU General Public License for more details at http://www.gnu.org * * */
344 var numbers
= ".0123456789" ;
345 function isNumeric ( x
) {
346 // is x a String or a character?
348 // remove negative sign
350 for ( var j
= 0 ; j
< x
. length
; j
++) {
351 // call isNumeric recursively for each character
352 number
= isNumeric ( x
. substring ( j
, j
+ 1 ));
353 if (! number
) return number
;
358 // if x is number return true
359 if ( numbers
. indexOf ( x
)>= 0 ) return true ;
365 function toggleSelectRowById ( sender
, id
) {
367 return toggleSelectRow ( sender
, row
);
370 function toggleSelectListRow ( sender
) {
371 var row
= sender
. parentNode
;
372 return toggleSelectRow ( sender
, row
);
375 /* this is for dijit Checkbox */
376 function toggleSelectListRow2 ( sender
) {
377 var row
= sender
. domNode
. parentNode
;
378 return toggleSelectRow ( sender
, row
);
381 /* this is for dijit Checkbox */
382 function toggleSelectRow2 ( sender
, row
, is_cdm
) {
386 row
= sender
. domNode
. parentNode
. parentNode
;
388 row
= sender
. domNode
. parentNode
. parentNode
. parentNode
; // oh ffs
390 if ( sender
. checked
&& ! row
. hasClassName ( 'Selected' ))
391 row
. addClassName ( 'Selected' );
393 row
. removeClassName ( 'Selected' );
395 if ( typeof updateSelectedPrompt
!= undefined )
396 updateSelectedPrompt ();
400 function toggleSelectRow ( sender
, row
) {
402 if (! row
) row
= sender
. parentNode
. parentNode
;
404 if ( sender
. checked
&& ! row
. hasClassName ( 'Selected' ))
405 row
. addClassName ( 'Selected' );
407 row
. removeClassName ( 'Selected' );
409 if ( typeof updateSelectedPrompt
!= undefined )
410 updateSelectedPrompt ();
413 function checkboxToggleElement ( elem
, id
) {
415 Effect
. Appear ( id
, { duration
: 0.5 });
417 Effect
. Fade ( id
, { duration
: 0.5 });
421 function dropboxSelect ( e
, v
) {
422 for ( var i
= 0 ; i
< e
. length
; i
++) {
423 if ( e
[ i
]. value
== v
) {
430 function getURLParam ( param
){
431 return String ( window
. location
. href
). parseQuery ()[ param
];
434 function closeInfoBox ( cleanup
) {
436 dialog
= dijit
. byId ( "infoBox" );
438 if ( dialog
) dialog
. hide ();
441 //exception_error("closeInfoBox", e);
447 function displayDlg ( title
, id
, param
, callback
) {
449 notify_progress ( "Loading, please wait..." , true );
451 var query
= "?op=dlg&method=" +
452 param_escape ( id
) + "¶m=" + param_escape ( param
);
454 new Ajax
. Request ( "backend.php" , {
456 onComplete : function ( transport
) {
457 infobox_callback2 ( transport
, title
);
458 if ( callback
) callback ( transport
);
464 function infobox_callback2 ( transport
, title
) {
468 if ( dijit
. byId ( "infoBox" )) {
469 dialog
= dijit
. byId ( "infoBox" );
472 //console.log("infobox_callback2");
475 var content
= transport
. responseText
;
478 dialog
= new dijit
. Dialog ({
481 style
: "width: 600px" ,
482 onCancel : function () {
485 onExecute : function () {
488 onClose : function () {
493 dialog
. attr ( 'title' , title
);
494 dialog
. attr ( 'content' , content
);
501 exception_error ( "infobox_callback2" , e
);
505 function getInitParam ( key
) {
506 return init_params
[ key
];
509 function setInitParam ( key
, value
) {
510 init_params
[ key
] = value
;
513 function fatalError ( code
, msg
, ext_info
) {
517 window
. location
. href
= "index.php" ;
518 } else if ( code
== 5 ) {
519 window
. location
. href
= "public.php?op=dbupdate" ;
522 if ( msg
== "" ) msg
= "Unknown error" ;
525 if ( ext_info
. responseText
) {
526 ext_info
= ext_info
. responseText
;
530 if ( ERRORS
&& ERRORS
[ code
] && ! msg
) {
534 var content
= "<div><b>Error code:</b> " + code
+ "</div>" +
535 "<p>" + msg
+ "</p>" ;
538 content
= content
+ "<div><b>Additional information:</b></div>" +
539 "<textarea style='width: 100%' readonly= \" 1 \" >" +
540 ext_info
+ "</textarea>" ;
543 var dialog
= new dijit
. Dialog ({
544 title
: "Fatal error" ,
545 style
: "width: 600px" ,
555 exception_error ( "fatalError" , e
);
559 function filterDlgCheckAction ( sender
) {
563 var action
= sender
. value
;
565 var action_param
= $( "filterDlg_paramBox" );
568 console
. log ( "filterDlgCheckAction: can't find action param box!" );
572 // if selected action supports parameters, enable params field
573 if ( action
== 4 || action
== 6 || action
== 7 || action
== 9 ) {
574 new Effect
. Appear ( action_param
, { duration
: 0.5 });
576 Element
. hide ( dijit
. byId ( "filterDlg_actionParam" ). domNode
);
577 Element
. hide ( dijit
. byId ( "filterDlg_actionParamLabel" ). domNode
);
578 Element
. hide ( dijit
. byId ( "filterDlg_actionParamPlugin" ). domNode
);
581 Element
. show ( dijit
. byId ( "filterDlg_actionParamLabel" ). domNode
);
582 } else if ( action
== 9 ) {
583 Element
. show ( dijit
. byId ( "filterDlg_actionParamPlugin" ). domNode
);
585 Element
. show ( dijit
. byId ( "filterDlg_actionParam" ). domNode
);
589 Element
. hide ( action_param
);
593 exception_error ( "filterDlgCheckAction" , e
);
599 function explainError ( code
) {
600 return displayDlg ( __ ( "Error explained" ), "explainError" , code
);
603 function loading_set_progress ( p
) {
605 loading_progress
+= p
;
607 if ( dijit
. byId ( "loading_bar" ))
608 dijit
. byId ( "loading_bar" ). update ({ progress
: loading_progress
});
610 if ( loading_progress
>= 90 )
614 exception_error ( "loading_set_progress" , e
);
618 function remove_splash () {
620 if ( Element
. visible ( "overlay" )) {
621 console
. log ( "about to remove splash, OMG!" );
622 Element
. hide ( "overlay" );
623 console
. log ( "removed splash!" );
627 function transport_error_check ( transport
) {
629 if ( transport
. responseXML
) {
630 var error
= transport
. responseXML
. getElementsByTagName ( "error" )[ 0 ];
633 var code
= error
. getAttribute ( "error-code" );
634 var msg
= error
. getAttribute ( "error-msg" );
636 fatalError ( code
, msg
);
642 exception_error ( "check_for_error_xml" , e
);
647 function strip_tags ( s
) {
648 return s
. replace ( /<\/?[^>]+(>|$)/g , "" );
651 function truncate_string ( s
, length
) {
652 if (! length
) length
= 30 ;
653 var tmp
= s
. substring ( 0 , length
);
654 if ( s
. length
> length
) tmp
+= "…" ;
658 function hotkey_prefix_timeout () {
661 var date
= new Date ();
662 var ts
= Math
. round ( date
. getTime () / 1000 );
664 if ( hotkey_prefix_pressed
&& ts
- hotkey_prefix_pressed
>= 5 ) {
665 console
. log ( "hotkey_prefix seems to be stuck, aborting" );
666 hotkey_prefix_pressed
= false ;
667 hotkey_prefix
= false ;
668 Element
. hide ( 'cmdline' );
671 setTimeout ( hotkey_prefix_timeout
, 1000 );
674 exception_error ( "hotkey_prefix_timeout" , e
);
678 function uploadIconHandler ( rc
) {
682 notify_info ( "Upload complete." );
683 if ( inPreferences ()) {
686 setTimeout ( 'updateFeedList(false, false)' , 50 );
690 notify_error ( "Upload failed: icon is too big." );
693 notify_error ( "Upload failed." );
698 exception_error ( "uploadIconHandler" , e
);
702 function removeFeedIcon ( id
) {
706 if ( confirm ( __ ( "Remove stored feed icon?" ))) {
707 var query
= "backend.php?op=pref-feeds&method=removeicon&feed_id=" + param_escape ( id
);
711 notify_progress ( "Removing feed icon..." , true );
713 new Ajax
. Request ( "backend.php" , {
715 onComplete : function ( transport
) {
716 notify_info ( "Feed icon removed." );
717 if ( inPreferences ()) {
720 setTimeout ( 'updateFeedList(false, false)' , 50 );
727 exception_error ( "removeFeedIcon" , e
);
731 function uploadFeedIcon () {
735 var file
= $( "icon_file" );
737 if ( file
. value
. length
== 0 ) {
738 alert ( __ ( "Please select an image file to upload." ));
740 if ( confirm ( __ ( "Upload new icon for this feed?" ))) {
741 notify_progress ( "Uploading, please wait..." , true );
749 exception_error ( "uploadFeedIcon" , e
);
753 function addLabel ( select
, callback
) {
757 var caption
= prompt ( __ ( "Please enter label caption:" ), "" );
759 if ( caption
!= undefined ) {
762 alert ( __ ( "Can't create label: missing caption." ));
766 var query
= "?op=pref-labels&method=add&caption=" +
767 param_escape ( caption
);
770 query
+= "&output=select" ;
772 notify_progress ( "Loading, please wait..." , true );
774 if ( inPreferences () && ! select
) active_tab
= "labelConfig" ;
776 new Ajax
. Request ( "backend.php" , {
778 onComplete : function ( transport
) {
781 } else if ( inPreferences ()) {
791 exception_error ( "addLabel" , e
);
795 function quickAddFeed () {
797 var query
= "backend.php?op=feeds&method=quickAddFeed" ;
799 // overlapping widgets
800 if ( dijit
. byId ( "batchSubDlg" )) dijit
. byId ( "batchSubDlg" ). destroyRecursive ();
801 if ( dijit
. byId ( "feedAddDlg" )) dijit
. byId ( "feedAddDlg" ). destroyRecursive ();
803 var dialog
= new dijit
. Dialog ({
805 title
: __ ( "Subscribe to Feed" ),
806 style
: "width: 600px" ,
807 show_error : function ( msg
) {
808 var elem
= $( "fadd_error_message" );
810 elem
. innerHTML
= msg
;
812 if (! Element
. visible ( elem
))
813 new Effect
. Appear ( elem
);
816 execute : function () {
817 if ( this . validate ()) {
818 console
. log ( dojo
. objectToQuery ( this . attr ( 'value' )));
820 var feed_url
= this . attr ( 'value' ). feed
;
822 Element
. show ( "feed_add_spinner" );
823 Element
. hide ( "fadd_error_message" );
825 new Ajax
. Request ( "backend.php" , {
826 parameters
: dojo
. objectToQuery ( this . attr ( 'value' )),
827 onComplete : function ( transport
) {
831 var reply
= JSON
. parse ( transport
. responseText
);
833 Element
. hide ( "feed_add_spinner" );
834 alert ( __ ( "Failed to parse output. This can indicate server timeout and/or network issues. Backend output was logged to browser console." ));
835 console
. log ( 'quickAddFeed, backend returned:' + transport
. responseText
);
839 var rc
= reply
[ 'result' ];
842 Element
. hide ( "feed_add_spinner" );
846 switch ( parseInt ( rc
[ 'code' ])) {
849 notify_info ( __ ( "Subscribed to %s" ). replace ( "%s" , feed_url
));
854 dialog
. show_error ( __ ( "Specified URL seems to be invalid." ));
857 dialog
. show_error ( __ ( "Specified URL doesn't seem to contain any feeds." ));
862 Element
. show ( "fadd_multiple_notify" );
864 var select
= dijit
. byId ( "feedDlg_feedContainerSelect" );
866 while ( select
. getOptions (). length
> 0 )
867 select
. removeOption ( 0 );
869 select
. addOption ({ value
: '' , label
: __ ( "Expand to select feed" )});
872 for ( var feedUrl
in feeds
) {
873 select
. addOption ({ value
: feedUrl
, label
: feeds
[ feedUrl
]});
877 Effect
. Appear ( 'feedDlg_feedsContainer' , { duration
: 0.5 });
881 dialog
. show_error ( __ ( "Couldn't download the specified URL: %s" ).
882 replace ( "%s" , rc
[ 'message' ]));
885 dialog
. show_error ( __ ( "XML validation failed: %s" ).
886 replace ( "%s" , rc
[ 'message' ]));
890 dialog
. show_error ( __ ( "You are already subscribed to this feed." ));
895 exception_error ( "subscribeToFeed" , e
, transport
);
906 exception_error ( "quickAddFeed" , e
);
910 function createNewRuleElement ( parentNode
, replaceNode
) {
912 var form
= document
. forms
[ "filter_new_rule_form" ];
914 //form.reg_exp.value = form.reg_exp.value.replace(/(<([^>]+)>)/ig,"");
916 var query
= "backend.php?op=pref-filters&method=printrulename&rule=" +
917 param_escape ( dojo
. formToJson ( form
));
921 new Ajax
. Request ( "backend.php" , {
923 onComplete : function ( transport
) {
925 var li
= dojo
. create ( "li" );
927 var cb
= dojo
. create ( "input" , { type
: "checkbox" }, li
);
929 new dijit
. form
. CheckBox ({
930 onChange : function () {
931 toggleSelectListRow2 ( this ) },
934 dojo
. create ( "input" , { type
: "hidden" ,
936 value
: dojo
. formToJson ( form
) }, li
);
938 dojo
. create ( "span" , {
939 onclick : function () {
940 dijit
. byId ( 'filterEditDlg' ). editRule ( this );
942 innerHTML
: transport
. responseText
}, li
);
945 parentNode
. replaceChild ( li
, replaceNode
);
947 parentNode
. appendChild ( li
);
950 exception_error ( "createNewRuleElement" , e
);
954 exception_error ( "createNewRuleElement" , e
);
958 function createNewActionElement ( parentNode
, replaceNode
) {
960 var form
= document
. forms
[ "filter_new_action_form" ];
962 if ( form
. action_id
. value
== 7 ) {
963 form
. action_param
. value
= form
. action_param_label
. value
;
964 } else if ( form
. action_id
. value
== 9 ) {
965 form
. action_param
. value
= form
. action_param_plugin
. value
;
968 var query
= "backend.php?op=pref-filters&method=printactionname&action=" +
969 param_escape ( dojo
. formToJson ( form
));
973 new Ajax
. Request ( "backend.php" , {
975 onComplete : function ( transport
) {
977 var li
= dojo
. create ( "li" );
979 var cb
= dojo
. create ( "input" , { type
: "checkbox" }, li
);
981 new dijit
. form
. CheckBox ({
982 onChange : function () {
983 toggleSelectListRow2 ( this ) },
986 dojo
. create ( "input" , { type
: "hidden" ,
988 value
: dojo
. formToJson ( form
) }, li
);
990 dojo
. create ( "span" , {
991 onclick : function () {
992 dijit
. byId ( 'filterEditDlg' ). editAction ( this );
994 innerHTML
: transport
. responseText
}, li
);
997 parentNode
. replaceChild ( li
, replaceNode
);
999 parentNode
. appendChild ( li
);
1003 exception_error ( "createNewActionElement" , e
);
1007 exception_error ( "createNewActionElement" , e
);
1012 function addFilterRule ( replaceNode
, ruleStr
) {
1014 if ( dijit
. byId ( "filterNewRuleDlg" ))
1015 dijit
. byId ( "filterNewRuleDlg" ). destroyRecursive ();
1017 var query
= "backend.php?op=pref-filters&method=newrule&rule=" +
1018 param_escape ( ruleStr
);
1020 var rule_dlg
= new dijit
. Dialog ({
1021 id
: "filterNewRuleDlg" ,
1022 title
: ruleStr
? __ ( "Edit rule" ) : __ ( "Add rule" ),
1023 style
: "width: 600px" ,
1024 execute : function () {
1025 if ( this . validate ()) {
1026 createNewRuleElement ($( "filterDlg_Matches" ), replaceNode
);
1034 exception_error ( "addFilterRule" , e
);
1038 function addFilterAction ( replaceNode
, actionStr
) {
1040 if ( dijit
. byId ( "filterNewActionDlg" ))
1041 dijit
. byId ( "filterNewActionDlg" ). destroyRecursive ();
1043 var query
= "backend.php?op=pref-filters&method=newaction&action=" +
1044 param_escape ( actionStr
);
1046 var rule_dlg
= new dijit
. Dialog ({
1047 id
: "filterNewActionDlg" ,
1048 title
: actionStr
? __ ( "Edit action" ) : __ ( "Add action" ),
1049 style
: "width: 600px" ,
1050 execute : function () {
1051 if ( this . validate ()) {
1052 createNewActionElement ($( "filterDlg_Actions" ), replaceNode
);
1060 exception_error ( "addFilterAction" , e
);
1064 function editFilterTest ( query
) {
1067 if ( dijit
. byId ( "filterTestDlg" ))
1068 dijit
. byId ( "filterTestDlg" ). destroyRecursive ();
1070 var test_dlg
= new dijit
. Dialog ({
1071 id
: "filterTestDlg" ,
1072 title
: "Test Filter" ,
1073 style
: "width: 600px" ,
1077 getTestResults : function ( query
, offset
) {
1078 var updquery
= query
+ "&offset=" + offset
+ "&limit=" + test_dlg
. limit
;
1080 console
. log ( "getTestResults:" + offset
);
1082 new Ajax
. Request ( "backend.php" , {
1083 parameters
: updquery
,
1084 onComplete : function ( transport
) {
1086 var result
= JSON
. parse ( transport
. responseText
);
1088 if ( result
&& dijit
. byId ( "filterTestDlg" ) && dijit
. byId ( "filterTestDlg" ). open
) {
1089 test_dlg
. results
+= result
. size ();
1091 console
. log ( "got results:" + result
. size ());
1093 $( "prefFilterProgressMsg" ). innerHTML
= __ ( "Looking for articles (%d processed, %f found)..." )
1094 . replace ( "%f" , test_dlg
. results
)
1095 . replace ( "%d" , offset
);
1097 console
. log ( offset
+ " " + test_dlg
. max_offset
);
1099 for ( var i
= 0 ; i
< result
. size (); i
++) {
1100 var tmp
= new Element ( "table" );
1101 tmp
. innerHTML
= result
[ i
];
1102 dojo
. parser
. parse ( tmp
);
1104 $( "prefFilterTestResultList" ). innerHTML
+= tmp
. innerHTML
;
1107 if ( test_dlg
. results
< 30 && offset
< test_dlg
. max_offset
) {
1109 // get the next batch
1110 window
. setTimeout ( function () {
1111 test_dlg
. getTestResults ( query
, offset
+ test_dlg
. limit
);
1117 Element
. hide ( "prefFilterLoadingIndicator" );
1119 if ( test_dlg
. results
== 0 ) {
1120 $( "prefFilterTestResultList" ). innerHTML
= "<tr><td align='center'>No recent articles matching this filter have been found.</td></tr>" ;
1121 $( "prefFilterProgressMsg" ). innerHTML
= "Articles matching this filter:" ;
1123 $( "prefFilterProgressMsg" ). innerHTML
= __ ( "Found %d articles matching this filter:" )
1124 . replace ( "%d" , test_dlg
. results
);
1129 } else if (! result
) {
1130 console
. log ( "getTestResults: can't parse results object" );
1132 Element
. hide ( "prefFilterLoadingIndicator" );
1134 notify_error ( "Error while trying to get filter test results." );
1137 console
. log ( "getTestResults: dialog closed, bailing out." );
1140 exception_error ( "editFilterTest/inner" , e
);
1147 dojo
. connect ( test_dlg
, "onLoad" , null , function ( e
) {
1148 test_dlg
. getTestResults ( query
, 0 );
1154 exception_error ( "editFilterTest" , e
);
1158 function quickAddFilter () {
1161 if (! inPreferences ()) {
1162 query
= "backend.php?op=pref-filters&method=newfilter&feed=" +
1163 param_escape ( getActiveFeedId ()) + "&is_cat=" +
1164 param_escape ( activeFeedIsCat ());
1166 query
= "backend.php?op=pref-filters&method=newfilter" ;
1171 if ( dijit
. byId ( "feedEditDlg" ))
1172 dijit
. byId ( "feedEditDlg" ). destroyRecursive ();
1174 if ( dijit
. byId ( "filterEditDlg" ))
1175 dijit
. byId ( "filterEditDlg" ). destroyRecursive ();
1177 dialog
= new dijit
. Dialog ({
1178 id
: "filterEditDlg" ,
1179 title
: __ ( "Create Filter" ),
1180 style
: "width: 600px" ,
1182 var query
= "backend.php?" + dojo
. formToQuery ( "filter_new_form" ) + "&savemode=test" ;
1184 editFilterTest ( query
);
1186 selectRules : function ( select
) {
1187 $$( "#filterDlg_Matches input[type=checkbox]" ). each ( function ( e
) {
1190 e
. parentNode
. addClassName ( "Selected" );
1192 e
. parentNode
. removeClassName ( "Selected" );
1195 selectActions : function ( select
) {
1196 $$( "#filterDlg_Actions input[type=checkbox]" ). each ( function ( e
) {
1200 e
. parentNode
. addClassName ( "Selected" );
1202 e
. parentNode
. removeClassName ( "Selected" );
1206 editRule : function ( e
) {
1207 var li
= e
. parentNode
;
1208 var rule
= li
. getElementsByTagName ( "INPUT" )[ 1 ]. value
;
1209 addFilterRule ( li
, rule
);
1211 editAction : function ( e
) {
1212 var li
= e
. parentNode
;
1213 var action
= li
. getElementsByTagName ( "INPUT" )[ 1 ]. value
;
1214 addFilterAction ( li
, action
);
1216 addAction : function () { addFilterAction (); },
1217 addRule : function () { addFilterRule (); },
1218 deleteAction : function () {
1219 $$( "#filterDlg_Actions li.[class*=Selected]" ). each ( function ( e
) { e
. parentNode
. removeChild ( e
) });
1221 deleteRule : function () {
1222 $$( "#filterDlg_Matches li.[class*=Selected]" ). each ( function ( e
) { e
. parentNode
. removeChild ( e
) });
1224 execute : function () {
1225 if ( this . validate ()) {
1227 var query
= dojo
. formToQuery ( "filter_new_form" );
1231 new Ajax
. Request ( "backend.php" , {
1233 onComplete : function ( transport
) {
1234 if ( inPreferences ()) {
1244 if (! inPreferences ()) {
1245 var selectedText
= getSelectionText ();
1247 var lh
= dojo
. connect ( dialog
, "onLoad" , function (){
1248 dojo
. disconnect ( lh
);
1250 if ( selectedText
!= "" ) {
1252 var feed_id
= activeFeedIsCat () ? 'CAT:' + parseInt ( getActiveFeedId ()) :
1255 var rule
= { reg_exp
: selectedText
, feed_id
: feed_id
, filter_type
: 1 };
1257 addFilterRule ( null , dojo
. toJson ( rule
));
1261 var query
= "op=rpc&method=getlinktitlebyid&id=" + getActiveArticleId ();
1263 new Ajax
. Request ( "backend.php" , {
1265 onComplete : function ( transport
) {
1266 var reply
= JSON
. parse ( transport
. responseText
);
1270 if ( reply
&& reply
) title
= reply
. title
;
1272 if ( title
|| getActiveFeedId () || activeFeedIsCat ()) {
1274 console
. log ( title
+ " " + getActiveFeedId ());
1276 var feed_id
= activeFeedIsCat () ? 'CAT:' + parseInt ( getActiveFeedId ()) :
1279 var rule
= { reg_exp
: title
, feed_id
: feed_id
, filter_type
: 1 };
1281 addFilterRule ( null , dojo
. toJson ( rule
));
1294 exception_error ( "quickAddFilter" , e
);
1298 function resetPubSub ( feed_id
, title
) {
1300 var msg
= __ ( "Reset subscription? Tiny Tiny RSS will try to subscribe to the notification hub again on next feed update." ). replace ( "%s" , title
);
1302 if ( title
== undefined || confirm ( msg
)) {
1303 notify_progress ( "Loading, please wait..." );
1305 var query
= "?op=pref-feeds&quiet=1&method=resetPubSub&ids=" + feed_id
;
1307 new Ajax
. Request ( "backend.php" , {
1309 onComplete : function ( transport
) {
1310 dijit
. byId ( "pubsubReset_Btn" ). attr ( 'disabled' , true );
1311 notify_info ( "Subscription reset." );
1319 function unsubscribeFeed ( feed_id
, title
) {
1321 var msg
= __ ( "Unsubscribe from %s?" ). replace ( "%s" , title
);
1323 if ( title
== undefined || confirm ( msg
)) {
1324 notify_progress ( "Removing feed..." );
1326 var query
= "?op=pref-feeds&quiet=1&method=remove&ids=" + feed_id
;
1328 new Ajax
. Request ( "backend.php" , {
1330 onComplete : function ( transport
) {
1332 if ( dijit
. byId ( "feedEditDlg" )) dijit
. byId ( "feedEditDlg" ). hide ();
1334 if ( inPreferences ()) {
1337 if ( feed_id
== getActiveFeedId ())
1338 setTimeout ( function () { viewfeed ({ feed
:- 5 }) }, 100 );
1340 if ( feed_id
< 0 ) updateFeedList ();
1350 function backend_sanity_check_callback ( transport
) {
1354 if ( sanity_check_done
) {
1355 fatalError ( 11 , "Sanity check request received twice. This can indicate " +
1356 "presence of Firebug or some other disrupting extension. " +
1357 "Please disable it and try again." );
1361 var reply
= JSON
. parse ( transport
. responseText
);
1364 fatalError ( 3 , "Sanity check: invalid RPC reply" , transport
. responseText
);
1368 var error_code
= reply
[ 'error' ][ 'code' ];
1370 if ( error_code
&& error_code
!= 0 ) {
1371 return fatalError ( error_code
, reply
[ 'error' ][ 'message' ]);
1374 console
. log ( "sanity check ok" );
1376 var params
= reply
[ 'init-params' ];
1379 console
. log ( 'reading init-params...' );
1382 console
. log ( "IP: " + k
+ " => " + JSON
. stringify ( params
[ k
]));
1383 if ( k
== "label_base_index" ) _label_base_index
= parseInt ( params
[ k
]);
1386 init_params
= params
;
1388 // PluginHost might not be available on non-index pages
1389 window
. PluginHost
&& PluginHost
. run ( PluginHost
. HOOK_PARAMS_LOADED
, init_params
);
1392 sanity_check_done
= true ;
1394 init_second_stage ();
1397 exception_error ( "backend_sanity_check_callback" , e
, transport
);
1401 /*function has_local_storage() {
1403 return 'sessionStorage' in window && window['sessionStorage'] != null;
1409 function catSelectOnChange ( elem
) {
1411 /* var value = elem[elem.selectedIndex].value;
1412 var def = elem.getAttribute('default');
1414 if (value == "ADD_CAT") {
1417 dropboxSelect(elem, def);
1419 elem.selectedIndex = 0;
1425 exception_error ( "catSelectOnChange" , e
);
1429 function quickAddCat ( elem
) {
1431 var cat
= prompt ( __ ( "Please enter category title:" ));
1435 var query
= "?op=rpc&method=quickAddCat&cat=" + param_escape ( cat
);
1437 notify_progress ( "Loading, please wait..." , true );
1439 new Ajax
. Request ( "backend.php" , {
1441 onComplete : function ( transport
) {
1442 var response
= transport
. responseXML
;
1443 var select
= response
. getElementsByTagName ( "select" )[ 0 ];
1444 var options
= select
. getElementsByTagName ( "option" );
1446 dropbox_replace_options ( elem
, options
);
1455 exception_error ( "quickAddCat" , e
);
1459 function genUrlChangeKey ( feed
, is_cat
) {
1462 var ok
= confirm ( __ ( "Generate new syndication address for this feed?" ));
1466 notify_progress ( "Trying to change address..." , true );
1468 var query
= "?op=pref-feeds&method=regenFeedKey&id=" + param_escape ( feed
) +
1469 "&is_cat=" + param_escape ( is_cat
);
1471 new Ajax
. Request ( "backend.php" , {
1473 onComplete : function ( transport
) {
1474 var reply
= JSON
. parse ( transport
. responseText
);
1475 var new_link
= reply
. link
;
1477 var e
= $( 'gen_feed_url' );
1481 e
. innerHTML
= e
. innerHTML
. replace ( /\&key=.*$/ ,
1482 "&key=" + new_link
);
1484 e
. href
= e
. href
. replace ( /\&key=.*$/ ,
1485 "&key=" + new_link
);
1487 new Effect
. Highlight ( e
);
1492 notify_error ( "Could not change feed URL." );
1497 exception_error ( "genUrlChangeKey" , e
);
1502 function labelSelectOnChange ( elem
) {
1504 /* var value = elem[elem.selectedIndex].value;
1505 var def = elem.getAttribute('default');
1507 if (value == "ADD_LABEL") {
1510 dropboxSelect(elem, def);
1512 elem.selectedIndex = 0;
1514 addLabel(elem, function(transport) {
1518 var response = transport.responseXML;
1519 var select = response.getElementsByTagName("select")[0];
1520 var options = select.getElementsByTagName("option");
1522 dropbox_replace_options(elem, options);
1526 exception_error("addLabel", e);
1532 exception_error ( "labelSelectOnChange" , e
);
1536 function dropbox_replace_options ( elem
, options
) {
1539 while ( elem
. hasChildNodes ())
1540 elem
. removeChild ( elem
. firstChild
);
1544 for ( var i
= 0 ; i
< options
. length
; i
++) {
1545 var text
= options
[ i
]. firstChild
. nodeValue
;
1546 var value
= options
[ i
]. getAttribute ( "value" );
1548 if ( value
== undefined ) value
= text
;
1550 var issel
= options
[ i
]. getAttribute ( "selected" ) == "1" ;
1552 var option
= new Option ( text
, value
, issel
);
1554 if ( options
[ i
]. getAttribute ( "disabled" ))
1555 option
. setAttribute ( "disabled" , true );
1557 elem
. insert ( option
);
1559 if ( issel
) sel_idx
= i
;
1562 // Chrome doesn't seem to just select stuff when you pass new Option(x, y, true)
1563 if ( sel_idx
>= 0 ) elem
. selectedIndex
= sel_idx
;
1566 exception_error ( "dropbox_replace_options" , e
);
1570 // mode = all, none, invert
1571 function selectTableRows ( id
, mode
) {
1573 var rows
= $( id
). rows
;
1575 for ( var i
= 0 ; i
< rows
. length
; i
++) {
1580 if ( row
. id
&& row
. className
) {
1581 var bare_id
= row
. id
. replace ( /^[A-Z]*?-/ , "" );
1582 var inputs
= rows
[ i
]. getElementsByTagName ( "input" );
1584 for ( var j
= 0 ; j
< inputs
. length
; j
++) {
1585 var input
= inputs
[ j
];
1587 if ( input
. getAttribute ( "type" ) == "checkbox" &&
1588 input
. id
. match ( bare_id
)) {
1591 dcb
= dijit
. getEnclosingWidget ( cb
);
1597 var issel
= row
. hasClassName ( "Selected" );
1599 if ( mode
== "all" && ! issel
) {
1600 row
. addClassName ( "Selected" );
1602 if ( dcb
) dcb
. set ( "checked" , true );
1603 } else if ( mode
== "none" && issel
) {
1604 row
. removeClassName ( "Selected" );
1606 if ( dcb
) dcb
. set ( "checked" , false );
1608 } else if ( mode
== "invert" ) {
1611 row
. removeClassName ( "Selected" );
1613 if ( dcb
) dcb
. set ( "checked" , false );
1615 row
. addClassName ( "Selected" );
1617 if ( dcb
) dcb
. set ( "checked" , true );
1625 exception_error ( "selectTableRows" , e
);
1630 function getSelectedTableRowIds ( id
) {
1634 var elem_rows
= $( id
). rows
;
1636 for ( var i
= 0 ; i
< elem_rows
. length
; i
++) {
1637 if ( elem_rows
[ i
]. hasClassName ( "Selected" )) {
1638 var bare_id
= elem_rows
[ i
]. id
. replace ( /^[A-Z]*?-/ , "" );
1644 exception_error ( "getSelectedTableRowIds" , e
);
1650 function editFeed ( feed
, event
) {
1653 return alert ( __ ( "You can't edit this kind of feed." ));
1655 var query
= "backend.php?op=pref-feeds&method=editfeed&id=" +
1660 if ( dijit
. byId ( "filterEditDlg" ))
1661 dijit
. byId ( "filterEditDlg" ). destroyRecursive ();
1663 if ( dijit
. byId ( "feedEditDlg" ))
1664 dijit
. byId ( "feedEditDlg" ). destroyRecursive ();
1666 dialog
= new dijit
. Dialog ({
1668 title
: __ ( "Edit Feed" ),
1669 style
: "width: 600px" ,
1670 execute : function () {
1671 if ( this . validate ()) {
1672 // console.log(dojo.objectToQuery(this.attr('value')));
1674 notify_progress ( "Saving data..." , true );
1676 new Ajax
. Request ( "backend.php" , {
1677 parameters
: dojo
. objectToQuery ( dialog
. attr ( 'value' )),
1678 onComplete : function ( transport
) {
1690 exception_error ( "editFeed" , e
);
1694 function feedBrowser () {
1696 var query
= "backend.php?op=feeds&method=feedBrowser" ;
1698 if ( dijit
. byId ( "feedAddDlg" ))
1699 dijit
. byId ( "feedAddDlg" ). hide ();
1701 if ( dijit
. byId ( "feedBrowserDlg" ))
1702 dijit
. byId ( "feedBrowserDlg" ). destroyRecursive ();
1704 var dialog
= new dijit
. Dialog ({
1705 id
: "feedBrowserDlg" ,
1706 title
: __ ( "More Feeds" ),
1707 style
: "width: 600px" ,
1708 getSelectedFeedIds : function () {
1709 var list
= $$( "#browseFeedList li[id*=FBROW]" );
1710 var selected
= new Array ();
1712 list
. each ( function ( child
) {
1713 var id
= child
. id
. replace ( "FBROW-" , "" );
1715 if ( child
. hasClassName ( 'Selected' )) {
1722 getSelectedFeeds : function () {
1723 var list
= $$( "#browseFeedList li.Selected" );
1724 var selected
= new Array ();
1726 list
. each ( function ( child
) {
1727 var title
= child
. getElementsBySelector ( "span.fb_feedTitle" )[ 0 ]. innerHTML
;
1728 var url
= child
. getElementsBySelector ( "a.fb_feedUrl" )[ 0 ]. href
;
1730 selected
. push ([ title
, url
]);
1737 subscribe : function () {
1738 var mode
= this . attr ( 'value' ). mode
;
1742 selected
= this . getSelectedFeeds ();
1744 selected
= this . getSelectedFeedIds ();
1746 if ( selected
. length
> 0 ) {
1747 dijit
. byId ( "feedBrowserDlg" ). hide ();
1749 notify_progress ( "Loading, please wait..." , true );
1751 // we use dojo.toJson instead of JSON.stringify because
1752 // it somehow escapes everything TWICE, at least in Chrome 9
1754 var query
= "?op=rpc&method=massSubscribe&payload=" +
1755 param_escape ( dojo
. toJson ( selected
)) + "&mode=" + param_escape ( mode
);
1759 new Ajax
. Request ( "backend.php" , {
1761 onComplete : function ( transport
) {
1767 alert ( __ ( "No feeds are selected." ));
1771 update : function () {
1772 var query
= dojo
. objectToQuery ( dialog
. attr ( 'value' ));
1774 Element
. show ( 'feed_browser_spinner' );
1776 new Ajax
. Request ( "backend.php" , {
1778 onComplete : function ( transport
) {
1781 Element
. hide ( 'feed_browser_spinner' );
1783 var c
= $( "browseFeedList" );
1785 var reply
= JSON
. parse ( transport
. responseText
);
1787 var r
= reply
[ 'content' ];
1788 var mode
= reply
[ 'mode' ];
1794 dojo
. parser
. parse ( "browseFeedList" );
1797 Element
. show ( dijit
. byId ( 'feed_archive_remove' ). domNode
);
1799 Element
. hide ( dijit
. byId ( 'feed_archive_remove' ). domNode
);
1804 removeFromArchive : function () {
1805 var selected
= this . getSelectedFeedIds ();
1807 if ( selected
. length
> 0 ) {
1809 var pr
= __ ( "Remove selected feeds from the archive? Feeds with stored articles will not be removed." );
1812 Element
. show ( 'feed_browser_spinner' );
1814 var query
= "?op=rpc&method=remarchive&ids=" +
1815 param_escape ( selected
. toString ());;
1817 new Ajax
. Request ( "backend.php" , {
1819 onComplete : function ( transport
) {
1825 execute : function () {
1826 if ( this . validate ()) {
1835 exception_error ( "editFeed" , e
);
1839 function showFeedsWithErrors () {
1841 var query
= "backend.php?op=pref-feeds&method=feedsWithErrors" ;
1843 if ( dijit
. byId ( "errorFeedsDlg" ))
1844 dijit
. byId ( "errorFeedsDlg" ). destroyRecursive ();
1846 dialog
= new dijit
. Dialog ({
1847 id
: "errorFeedsDlg" ,
1848 title
: __ ( "Feeds with update errors" ),
1849 style
: "width: 600px" ,
1850 getSelectedFeeds : function () {
1851 return getSelectedTableRowIds ( "prefErrorFeedList" );
1853 removeSelected : function () {
1854 var sel_rows
= this . getSelectedFeeds ();
1856 console
. log ( sel_rows
);
1858 if ( sel_rows
. length
> 0 ) {
1859 var ok
= confirm ( __ ( "Remove selected feeds?" ));
1862 notify_progress ( "Removing selected feeds..." , true );
1864 var query
= "?op=pref-feeds&method=remove&ids=" +
1865 param_escape ( sel_rows
. toString ());
1867 new Ajax
. Request ( "backend.php" , {
1869 onComplete : function ( transport
) {
1877 alert ( __ ( "No feeds are selected." ));
1880 execute : function () {
1881 if ( this . validate ()) {
1889 exception_error ( "showFeedsWithErrors" , e
);
1894 /* new support functions for SelectByTag */
1896 function get_all_tags ( selObj
){
1898 if ( ! selObj
) return "" ;
1901 var len
= selObj
. options
. length
;
1903 for ( var i
= 0 ; i
< len
; i
++){
1904 if ( selObj
. options
[ i
]. selected
) {
1905 result
+= selObj
[ i
]. value
+ "%2C" ; // is really a comma
1909 if ( result
. length
> 0 ){
1910 result
= result
. substr ( 0 , result
. length
- 3 ); // remove trailing %2C
1916 exception_error ( "get_all_tags" , e
);
1920 function get_radio_checked ( radioObj
) {
1922 if (! radioObj
) return "" ;
1924 var len
= radioObj
. length
;
1926 if ( len
== undefined ){
1927 if ( radioObj
. checked
){
1928 return ( radioObj
. value
);
1934 for ( var i
= 0 ; i
< len
; i
++ ){
1935 if ( radioObj
[ i
]. checked
){
1936 return ( radioObj
[ i
]. value
);
1941 exception_error ( "get_radio_checked" , e
);
1946 function get_timestamp () {
1947 var date
= new Date ();
1948 return Math
. round ( date
. getTime () / 1000 );
1951 function helpDialog ( topic
) {
1953 var query
= "backend.php?op=backend&method=help&topic=" + param_escape ( topic
);
1955 if ( dijit
. byId ( "helpDlg" ))
1956 dijit
. byId ( "helpDlg" ). destroyRecursive ();
1958 dialog
= new dijit
. Dialog ({
1961 style
: "width: 600px" ,
1968 exception_error ( "helpDialog" , e
);
1972 function htmlspecialchars_decode ( string
, quote_style
) {
1973 // http://kevin.vanzonneveld.net
1974 // + original by: Mirek Slugen
1975 // + improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
1976 // + bugfixed by: Mateusz "loonquawl" Zalega
1977 // + input by: ReverseSyntax
1978 // + input by: Slawomir Kaniecki
1979 // + input by: Scott Cariss
1980 // + input by: Francois
1981 // + bugfixed by: Onno Marsman
1982 // + revised by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
1983 // + bugfixed by: Brett Zamir (http://brett-zamir.me)
1984 // + input by: Ratheous
1985 // + input by: Mailfaker (http://www.weedem.fr/)
1986 // + reimplemented by: Brett Zamir (http://brett-zamir.me)
1987 // + bugfixed by: Brett Zamir (http://brett-zamir.me)
1988 // * example 1: htmlspecialchars_decode("<p>this -> "</p>", 'ENT_NOQUOTES');
1989 // * returns 1: '<p>this -> "</p>'
1990 // * example 2: htmlspecialchars_decode("&quot;");
1991 // * returns 2: '"'
1995 if ( typeof quote_style
=== 'undefined' ) {
1998 string
= string
. toString (). replace ( /</g , '<' ). replace ( />/g , '>' );
2001 'ENT_HTML_QUOTE_SINGLE' : 1 ,
2002 'ENT_HTML_QUOTE_DOUBLE' : 2 ,
2007 if ( quote_style
=== 0 ) {
2010 if ( typeof quote_style
!== 'number' ) { // Allow for a single string or an array of string flags
2011 quote_style
= []. concat ( quote_style
);
2012 for ( i
= 0 ; i
< quote_style
. length
; i
++) {
2013 // Resolve string input to bitwise e.g. 'PATHINFO_EXTENSION' becomes 4
2014 if ( OPTS
[ quote_style
[ i
]] === 0 ) {
2016 } else if ( OPTS
[ quote_style
[ i
]]) {
2017 optTemp
= optTemp
| OPTS
[ quote_style
[ i
]];
2020 quote_style
= optTemp
;
2022 if ( quote_style
& OPTS
. ENT_HTML_QUOTE_SINGLE
) {
2023 string
= string
. replace ( /�*39;/g , "'" ); // PHP doesn't currently escape if more than one 0, but it should
2024 // string = string.replace(/'|�*27;/g, "'"); // This would also be useful here, but not a part of PHP
2027 string
= string
. replace ( /"/g , '"' );
2029 // Put this in last place to avoid escape being double-decoded
2030 string
= string
. replace ( /&/g , '&' );
2036 function label_to_feed_id ( label
) {
2037 return _label_base_index
- 1 - Math
. abs ( label
);
2040 function feed_to_label_id ( feed
) {
2041 return _label_base_index
- 1 + Math
. abs ( feed
);
2044 // http://stackoverflow.com/questions/6251937/how-to-get-selecteduser-highlighted-text-in-contenteditable-element-and-replac
2046 function getSelectionText () {
2049 if ( typeof window
. getSelection
!= "undefined" ) {
2050 var sel
= window
. getSelection ();
2051 if ( sel
. rangeCount
) {
2052 var container
= document
. createElement ( "div" );
2053 for ( var i
= 0 , len
= sel
. rangeCount
; i
< len
; ++ i
) {
2054 container
. appendChild ( sel
. getRangeAt ( i
). cloneContents ());
2056 text
= container
. innerHTML
;
2058 } else if ( typeof document
. selection
!= "undefined" ) {
2059 if ( document
. selection
. type
== "Text" ) {
2060 text
= document
. selection
. createRange (). textText
;
2064 return text
. stripTags ();
2067 function openUrlPopup ( url
) {
2068 var w
= window
. open ( "" );
2073 function openArticlePopup ( id
) {
2074 var w
= window
. open ( "" ,
2075 "ttrss_article_popup" ,
2076 "height=900,width=900,resizable=yes,status=no,location=no,menubar=no,directories=no,scrollbars=yes,toolbar=no" );
2079 w
. location
= "backend.php?op=article&method=view&mode=raw&html=1&zoom=1&id=" + id
+ "&csrf_token=" + getInitParam ( "csrf_token" );