diff --git a/ajaxui/ajaxui.c b/ajaxui/ajaxui.c deleted file mode 100644 index 5340b82e..00000000 --- a/ajaxui/ajaxui.c +++ /dev/null @@ -1,686 +0,0 @@ -/* - * tvheadend, AJAX / HTML user interface - * Copyright (C) 2008 Andreas Öman - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include -#include -#include -#include -#include -#include - -#include "tvhead.h" -#include "http.h" -#include "ajaxui.h" -#include "ajaxui_mailbox.h" -#include "dispatch.h" - -#include "obj/ajaxui.cssh" - -#include "obj/prototype.jsh" -#include "obj/builder.jsh" -#include "obj/controls.jsh" -#include "obj/dragdrop.jsh" -#include "obj/effects.jsh" -#include "obj/scriptaculous.jsh" -#include "obj/slider.jsh" - -#include "obj/tvheadend.jsh" - -#include "obj/sbbody_l.gifh" -#include "obj/sbbody_r.gifh" -#include "obj/sbhead_l.gifh" -#include "obj/sbhead_r.gifh" - -#include "obj/mapped.pngh" -#include "obj/unmapped.pngh" - - -extern const char *htsversion; - -const char *ajax_tabnames[] = { - [AJAX_TAB_CHANNELS] = "Channels", - [AJAX_TAB_RECORDER] = "Recorder", - [AJAX_TAB_CONFIGURATION] = "Configuration", - [AJAX_TAB_ABOUT] = "About", -}; - - -const char * -ajaxui_escape_apostrophe(const char *content) -{ - static char buf[2000]; - int i = 0; - - while(i < sizeof(buf) - 2 && *content) { - if(*content == '\'') - buf[i++] = '\\'; - buf[i++] = *content++; - } - buf[i] = 0; - return buf; -} - - -/** - * - */ -void -ajax_generate_select_functions(htsbuf_queue_t *hq, const char *fprefix, - char **selvector) -{ - int n; - - htsbuf_qprintf(hq, "\r\n"); -} - - -/** - * AJAX table - */ -void -ajax_table_top(ajax_table_t *t, http_connection_t *hc, htsbuf_queue_t *hq, - const char *names[], int weights[]) -{ - int n = 0, i, tw = 0; - while(names[n]) { - tw += weights[n]; - n++; - } - assert(n <= 20); - - t->columns = n; - - memset(t, 0, sizeof(ajax_table_t)); - - t->hq = hq; - - for(i = 0; i < n; i++) - t->csize[i] = 100 * weights[i] / tw; - - htsbuf_qprintf(hq, "
"); - - htsbuf_qprintf(hq, "
"); - - for(i = 0; i < n; i++) - htsbuf_qprintf(hq, "
%s
", - t->csize[i], *names[i] ? names[i]: " "); - htsbuf_qprintf(hq, "

\r\n"); -} - -/** - * AJAX table new row - */ -void -ajax_table_row_start(ajax_table_t *t, const char *id) -{ - t->rowid = id; - t->rowcol = !t->rowcol; - htsbuf_qprintf(t->hq, "%s
", - t->inrow ? "
\r\n" : "", - t->rowcol ? "background: #fff; " : ""); - t->inrow = 1; - t->curcol = 0; -} - -/** - * AJAX table new row - */ -void -ajax_table_subrow_start(ajax_table_t *t) -{ - htsbuf_qprintf(t->hq, "
"); - t->curcol = 0; -} - - -/** - * AJAX table new row - */ -void -ajax_table_subrow_end(ajax_table_t *t) -{ - htsbuf_qprintf(t->hq, "
"); - t->curcol = 0; -} - - -/** - * AJAX table new row - */ -void -ajax_table_details_start(ajax_table_t *t) -{ - assert(t->inrow == 1); - t->inrow = 0; - /* Extra info */ - htsbuf_qprintf(t->hq, "
", - t->rowid, t->rowcol ? "background: #fff; " : ""); -} - -/** - * AJAX table new row - */ -void -ajax_table_details_end(ajax_table_t *t) -{ - /* Extra info */ - htsbuf_qprintf(t->hq, "
"); -} - - -/** - * AJAX table cell - */ -void -ajax_table_cell(ajax_table_t *t, const char *id, const char *fmt, ...) -{ - va_list ap; - va_start(ap, fmt); - - if(t->rowid && id) { - htsbuf_qprintf(t->hq, "
rowid); - } else { - htsbuf_qprintf(t->hq, "hq, - " style=\"float: left; width: %d%%\">", t->csize[t->curcol]); - t->curcol++; - if(t->curcol == 20) - abort(); - - if(fmt == NULL) - htsbuf_qprintf(t->hq, " "); - else - htsbuf_vqprintf(t->hq, fmt, ap); - - va_end(ap); - htsbuf_qprintf(t->hq, "
"); -} - -/** - * AJAX table cell for toggling display of more details - */ -void -ajax_table_cell_detail_toggler(ajax_table_t *t) -{ - ajax_table_cell(t, NULL, - "" - "More", - t->rowid, t->rowid); -} - -/** - * AJAX table cell for selecting row - */ -void -ajax_table_cell_checkbox(ajax_table_t *t) -{ - ajax_table_cell(t, NULL, - "", - t->rowid); -} - -/** - * AJAX table footer - */ -void -ajax_table_bottom(ajax_table_t *t) -{ - htsbuf_qprintf(t->hq, "%s", t->inrow ? "" : ""); -} - -/** - * AJAX box start - */ -void -ajax_box_begin(htsbuf_queue_t *hq, ajax_box_t type, - const char *id, const char *style, const char *title) -{ - char id0[100], style0[100]; - - if(id != NULL) - snprintf(id0, sizeof(id0), "id=\"%s\" ", id); - else - id0[0] = 0; - - if(style != NULL) - snprintf(style0, sizeof(style0), "style=\"%s\" ", style); - else - style0[0] = 0; - - - switch(type) { - case AJAX_BOX_SIDEBOX: - htsbuf_qprintf(hq, - "
" - "

%s

\r\n" - "
", - title, id0, style0); - break; - - case AJAX_BOX_FILLED: - htsbuf_qprintf(hq, - "
" - "" - "" - "" - "" - "" - "" - "
\r\n", - id0, style0); - break; - - case AJAX_BOX_BORDER: - htsbuf_qprintf(hq, - "
" - "" - "" - "" - "" - "
\r\n", - id0, style0); - - break; - } -} - -/** - * AJAX box end - */ -void -ajax_box_end(htsbuf_queue_t *hq, ajax_box_t type) -{ - switch(type) { - case AJAX_BOX_SIDEBOX: - htsbuf_qprintf(hq,"
"); - break; - - case AJAX_BOX_FILLED: - htsbuf_qprintf(hq, - "
" - "" - "" - "" - "" - "" - "" - "
\r\n"); - break; - - case AJAX_BOX_BORDER: - htsbuf_qprintf(hq, - "
" - "" - "" - "" - "" - "
\r\n"); - break; - - } -} - -/** - * - */ -void -ajax_js(htsbuf_queue_t *hq, const char *fmt, ...) -{ - va_list ap; - - htsbuf_qprintf(hq, - "\r\n"); -} - - - -/** - * Based on the given char[] array, generate a menu bar - */ -void -ajax_menu_bar_from_array(htsbuf_queue_t *hq, const char *name, - const char **vec, int num, int cur) -{ - int i; - - htsbuf_qprintf(hq, "
    "); - - for(i = 0; i < num; i++) { - htsbuf_qprintf(hq, - "" - "%s" - "", - cur == i ? " style=\"font-weight:bold;\"" : "", name, - i, vec[i]); - } - htsbuf_qprintf(hq, "
"); -} - - -/** - * - */ -void -ajax_a_jsfuncf(htsbuf_queue_t *hq, const char *innerhtml, const char *fmt, ...) -{ - va_list ap; - va_start(ap, fmt); - - htsbuf_qprintf(hq, "%s", innerhtml); -} - -/** - * - */ -void -ajax_button(htsbuf_queue_t *hq, const char *caption, const char *code, ...) -{ - va_list ap; - va_start(ap, code); - - htsbuf_qprintf(hq, ""); -} - - - -/* - * Titlebar AJAX page - */ -static int -ajax_page_titlebar(http_connection_t *hc, http_reply_t *hr, - const char *remain, void *opaque) -{ - if(remain == NULL) - return HTTP_STATUS_NOT_FOUND; - - ajax_menu_bar_from_array(&hr->hr_q, "top", - ajax_tabnames, AJAX_TABS, atoi(remain)); - http_output_html(hc, hr); - return 0; -} - - - -/** - * About - */ -static int -ajax_about_tab(http_connection_t *hc, http_reply_t *hr) -{ - htsbuf_queue_t *hq = &hr->hr_q; - - htsbuf_qprintf(hq, "
"); - htsbuf_qprintf(hq, "
"); - - ajax_box_begin(hq, AJAX_BOX_SIDEBOX, NULL, NULL, "About"); - - htsbuf_qprintf(hq, "
"); - - htsbuf_qprintf(hq, - "

HTS / Tvheadend

" - "

(c) 2006-2008 Andreas \303\226man

" - "

Latest release and information is available at:

" - "

" - "http://www.lonelycoder.com/hts/

" - "

 

" - "

This webinterface is powered by

" - "

Prototype" - " and " - "script.aculo.us" - "

" - "

 

" - "

Media formats and codecs by

" - "

FFmpeg

" - ); - - htsbuf_qprintf(hq, "
"); - ajax_box_end(hq, AJAX_BOX_SIDEBOX); - htsbuf_qprintf(hq, "
"); - htsbuf_qprintf(hq, "
"); - - http_output_html(hc, hr); - return 0; -} - - - -/* - * Tab AJAX page - * - * Find the 'tab' id and continue with tab specific code - */ -static int -ajax_page_tab(http_connection_t *hc, http_reply_t *hr, - const char *remain, void *opaque) -{ - int tab; - - if(remain == NULL) - return HTTP_STATUS_NOT_FOUND; - - tab = atoi(remain); - - switch(tab) { - case AJAX_TAB_CHANNELS: - return ajax_channelgroup_tab(hc, hr); - - case AJAX_TAB_CONFIGURATION: - return ajax_config_tab(hc, hr); - - case AJAX_TAB_ABOUT: - return ajax_about_tab(hc, hr); - - default: - return HTTP_STATUS_NOT_FOUND; - } - return 0; -} - - - -/* - * Root page - */ -static int -ajax_page_root(http_connection_t *hc, http_reply_t *hr, - const char *remain, void *opaque) -{ - htsbuf_queue_t *hq = &hr->hr_q; - - htsbuf_qprintf(hq, - "" - /* - "" - */ - "\r\n" - "" - "" - "HTS/Tvheadend" - "\r\n" - "\r\n" - "\r\n" - "\r\n" - "\r\n" - "\r\n" - "\r\n" - "" - ""); - - - htsbuf_qprintf(hq, "
"); - - htsbuf_qprintf(hq, "
"); - - ajax_box_begin(hq, AJAX_BOX_FILLED, NULL, NULL, NULL); - - htsbuf_qprintf(hq, - "
" - "
" - "Tvheadend (%s)" - "
" - "
" - "
" - " " - "
" - "
", - htsversion); - - ajax_mailbox_start(hq); - - ajax_box_end(hq, AJAX_BOX_FILLED); - - htsbuf_qprintf(hq, "
"); - - ajax_js(hq, "switchtab('top', '0')"); -#if 0 - htsbuf_qprintf(hq, "
"); - - ajax_box_begin(hq, AJAX_BOX_SIDEBOX, "statusbox", NULL, "System status"); - ajax_box_end(hq, AJAX_BOX_SIDEBOX); -#endif - htsbuf_qprintf(hq, "
"); - - http_output_html(hc, hr); - return 0; -} - - -/** - * AJAX user interface - */ -void -ajaxui_start(void) -{ - http_path_add("/ajax/index.html", NULL, ajax_page_root, - ACCESS_WEB_INTERFACE); - - http_path_add("/ajax/topmenu", NULL, ajax_page_titlebar, - ACCESS_WEB_INTERFACE); - - http_path_add("/ajax/toptab", NULL, ajax_page_tab, - ACCESS_WEB_INTERFACE); - - /* Stylesheet */ - http_resource_add("/ajax/ajaxui.css", embedded_ajaxui, - sizeof(embedded_ajaxui), "text/css", "gzip"); - -#define ADD_JS_RESOURCE(path, name) \ - http_resource_add(path, name, sizeof(name), "text/javascript", "gzip") - - /* Prototype */ - ADD_JS_RESOURCE("/ajax/prototype.js", embedded_prototype); - - /* Scriptaculous */ - ADD_JS_RESOURCE("/ajax/builder.js", embedded_builder); - ADD_JS_RESOURCE("/ajax/controls.js", embedded_controls); - ADD_JS_RESOURCE("/ajax/dragdrop.js", embedded_dragdrop); - ADD_JS_RESOURCE("/ajax/effects.js", embedded_effects); - ADD_JS_RESOURCE("/ajax/scriptaculous.js", embedded_scriptaculous); - ADD_JS_RESOURCE("/ajax/slider.js", embedded_slider); - - /* Tvheadend */ - ADD_JS_RESOURCE("/ajax/tvheadend.js", embedded_tvheadend); - - /* Embedded images */ - http_resource_add("/sidebox/sbbody-l.gif", embedded_sbbody_l, - sizeof(embedded_sbbody_l), "image/gif", NULL); - http_resource_add("/sidebox/sbbody-r.gif", embedded_sbbody_r, - sizeof(embedded_sbbody_r), "image/gif", NULL); - http_resource_add("/sidebox/sbhead-l.gif", embedded_sbhead_l, - sizeof(embedded_sbhead_l), "image/gif", NULL); - http_resource_add("/sidebox/sbhead-r.gif", embedded_sbhead_r, - sizeof(embedded_sbhead_r), "image/gif", NULL); - - http_resource_add("/gfx/unmapped.png", embedded_unmapped, - sizeof(embedded_unmapped), "image/png", NULL); - - http_resource_add("/gfx/mapped.png", embedded_mapped, - sizeof(embedded_mapped), "image/png", NULL); - - ajax_mailbox_init(); - ajax_channels_init(); - ajax_config_init(); - ajax_config_transport_init(); -} diff --git a/ajaxui/ajaxui.css b/ajaxui/ajaxui.css deleted file mode 100644 index 84dd96b6..00000000 --- a/ajaxui/ajaxui.css +++ /dev/null @@ -1,329 +0,0 @@ -body { - font: 11px Lucida Grande, Verdana, Arial, Helvetica, sans serif; -} -select { - font: 11px Lucida Grande, Verdana, Arial, Helvetica, sans serif; -} -input { - font: 11px Lucida Grande, Verdana, Arial, Helvetica, sans serif; -} - - -a, a:hover, a:visited, a:active { - color: #aa6600; -} - -img { border: 0; } - -.draglist { - margin:0; - padding:0; - list-style-type: none; - } -.draglist li { - margin:0; - padding:0px; - cursor:move; - } - - - -.normallist { - margin:0; - margin-top:10px; - padding:0; - list-style-type: none; - } -.normallist li { - margin:0; - padding:0px; - } - -/** - * Input classes - */ - -.nicebox { - margin: 1px; - padding: 0px; - border: 0px; - width: 11px; - height: 11px; -} - - -/** - * Misc classes - */ - -.event3 { - height: 42px - -} - -.compact { - float: left; - height: 100%; - overflow: hidden; -} - -.fullrow { - overflow: auto; - width: 100%; - height: 14px; -} - -.cell_100_center { - margin-top: 2px; - margin-bottom: 2px; - width: 100%; - text-align: center; -} - -.cell_50 { - margin-top: 2px; - margin-bottom: 2px; - float: left; - width: 50%; -} - -.cell_20 { - margin-top: 2px; - margin-bottom: 2px; - float: left; - width: 20%; -} - -.normaltable { - height: 300px; - overflow: auto; - overflow-y: scroll; - overflow-x: hidden; - } - -.iconbackdrop { - background: #fff; - height: 64px; - width: 64px; - float: left; - margin: 2px; - text-align: center; - margin-right: 4px; -} - -.infoprefix { - float: left; - width: 50px; - text-align: right; -} - -.infoprefixwide { - padding-right: 5px; - float: left; - width: 100px; - text-align: right; -} - -.infoprefixwidefat { - padding-right: 5px; - float: left; - width: 100px; - text-align: right; - margin-top: 4px; -} - - -.infoprefixwidewidefat { - padding-right: 5px; - float: left; - width: 130px; - text-align: right; - margin-top: 4px; -} - -.pidheader { - float: left; - text-decoration: underline; -} - - - -.chgroupaction { - text-align: right; -} - - -/** - * Box with round edges - */ -.filledbox { - display:block; -} - -.filledbox * { - display:block; - height:1px; - overflow:hidden; - font-size:.01em; - background:#dddddd; -} - -.filledbox1 { - margin-left:3px; - margin-right:3px; - padding-left:1px; - padding-right:1px; - border-left:1px solid #f0f0f0; - border-right:1px solid #f0f0f0; - background:#e5e5e5; -} - -.filledbox2 { - margin-left:1px; - margin-right:1px; - padding-right:1px; - padding-left:1px; - border-left:1px solid #fbfbfb; - border-right:1px solid #fbfbfb; - background:#e3e3e3; -} - -.filledbox3 { - margin-left:1px; - margin-right:1px; - border-left:1px solid #e3e3e3; - border-right:1px solid #e3e3e3; -} - -.filledbox4 { - border-left:1px solid #f0f0f0; - border-right:1px solid #f0f0f0; -} - -.filledbox5 { - border-left:1px solid #e5e5e5; - border-right:1px solid #e5e5e5; -} - -.filledboxfg { - padding-left:5px; - padding-right:5px; - background:#dddddd; -} - - - - - -/** - * Box with rounded edges - */ -.borderbox { - display:block; -} - -.borderbox * { - display:block; - height:1px; - overflow:hidden; - font-size:.01em; -} - -.borderbox1 { - margin-left:4px; - margin-right:4px; - padding-left:1px; - padding-right:1px; - background: #000000; - border-left:1px solid #000; - border-right:1px solid #000; -} - -.borderbox2 { - margin-left:2px; - margin-right:2px; - padding-right:1px; - padding-left:1px; - border-left:2px solid #000; - border-right:2px solid #000; -} - -.borderbox3 { - margin-left:1px; - margin-right:1px; - border-left:1px solid #000; - border-right:1px solid #000; -} - - -.borderboxfg { - border-left:1px solid #000; - border-right:1px solid #000; - padding-left:5px; - padding-right:5px; -} - - - -/** - * Menubar - */ - -.menubar { - margin: 0px; - padding: 0px; - text-align: center; - height: 15px; -} - -.menubar li { - margin-left: 5px; - margin-right: 5px; - display: inline; - list-style-type: none; -} - -.menubar a { - color: #000000; - text-decoration: none; -} - - - - - -/** - * Sidebox - * - * from http://www.vertexwerks.com/tests/sidebox/ - */ - -/* Show only to IE PC \*/ -* html .boxhead h2 {height: 1%;} /* For IE 5 PC */ - -.sidebox { - margin: 0 auto; /* center for now */ - background: url(/sidebox/sbbody-r.gif) no-repeat bottom right; - font-size: 100%; -} -.boxhead { - background: url(/sidebox/sbhead-r.gif) no-repeat top right; - margin: 0; - padding: 0; - text-align: center; -} -.boxhead h2 { - background: url(/sidebox/sbhead-l.gif) no-repeat top left; - margin: 0; - padding: 22px 30px 5px; - color: white; - font-weight: bold; - font-size: 1.4em; - line-height: 1em; - text-shadow: rgba(0,0,0,.4) 0px 2px 5px; /* Safari-only, but cool */ -} -.boxbody { - background: url(/sidebox/sbbody-l.gif) no-repeat bottom left; - margin: 0; - padding: 5px 30px 31px; -} diff --git a/ajaxui/ajaxui.h b/ajaxui/ajaxui.h deleted file mode 100644 index 3f59d859..00000000 --- a/ajaxui/ajaxui.h +++ /dev/null @@ -1,127 +0,0 @@ -/* - * tvheadend, AJAX user interface - * Copyright (C) 2007 Andreas Öman - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef AJAXUI_H_ -#define AJAXUI_H_ - -#include "access.h" - -#define AJAX_ACCESS_CONFIG (ACCESS_WEB_INTERFACE | ACCESS_ADMIN) -#define AJAX_ACCESS_ACCESSCTRL \ - (ACCESS_WEB_INTERFACE | ACCESS_ADMIN | ACCESS_ADMIN_ACCESS) - -typedef enum { - AJAX_BOX_FILLED, - AJAX_BOX_SIDEBOX, - AJAX_BOX_BORDER, -} ajax_box_t; - - -void ajax_box_begin(htsbuf_queue_t *q, ajax_box_t type, - const char *id, const char *style, const char *title); - -void ajax_box_end(htsbuf_queue_t *q, ajax_box_t type); - - - -typedef struct { - int columns; - int curcol; - - int inrow; - const char *rowid; - - int csize[20]; - htsbuf_queue_t *hq; - int rowcol; -} ajax_table_t; - -void ajax_table_top(ajax_table_t *t, http_connection_t *hc, htsbuf_queue_t *q, - const char *names[], int weights[]); -void ajax_table_row_start(ajax_table_t *t, const char *id); -void ajax_table_cell(ajax_table_t *t, const char *id, const char *fmt, ...); -void ajax_table_bottom(ajax_table_t *t); -void ajax_table_cell_detail_toggler(ajax_table_t *t); -void ajax_table_cell_checkbox(ajax_table_t *t); -void ajax_table_details_start(ajax_table_t *t); -void ajax_table_details_end(ajax_table_t *t); -void ajax_table_subrow_start(ajax_table_t *t); -void ajax_table_subrow_end(ajax_table_t *t); - - - - -void ajax_js(htsbuf_queue_t *q, const char *fmt, ...); - - -TAILQ_HEAD(ajax_menu_entry_queue, ajax_menu_entry); - -#define AJAX_TAB_CHANNELS 0 -#define AJAX_TAB_RECORDER 1 -#define AJAX_TAB_CONFIGURATION 2 -#define AJAX_TAB_ABOUT 3 -#define AJAX_TABS 4 - - -void ajax_mailbox_init(void); -void ajaxui_start(void); -void ajax_channels_init(void); -void ajax_config_init(void); - -void ajax_menu_bar_from_array(htsbuf_queue_t *q, const char *name, - const char **vec, int num, int cur); - -int ajax_channelgroup_tab(http_connection_t *hc, http_reply_t *hr); -int ajax_config_tab(http_connection_t *hc, http_reply_t *hr); - -int ajax_config_channels_tab(http_connection_t *hc, http_reply_t *hr); -void ajax_config_channels_init(void); - -int ajax_config_dvb_tab(http_connection_t *hc, http_reply_t *hr); -void ajax_config_dvb_init(void); - -int ajax_config_xmltv_tab(http_connection_t *hc, http_reply_t *hr); -void ajax_config_xmltv_init(void); - -int ajax_config_access_tab(http_connection_t *hc, http_reply_t *hr); -void ajax_config_access_init(void); - -int ajax_config_cwc_tab(http_connection_t *hc, http_reply_t *hr); -void ajax_config_cwc_init(void); - -void ajax_config_transport_init(void); - -int ajax_transport_build_list(http_connection_t *hc, htsbuf_queue_t *q, - struct th_transport_tree *tlist, - int ntransports); - -const char *ajaxui_escape_apostrophe(const char *content); -void ajax_generate_select_functions(htsbuf_queue_t *q, const char *fprefix, - char **selvector); - -void ajax_a_jsfuncf(htsbuf_queue_t *q, const char *innerhtml, - const char *fmt, ...); - -void ajax_button(htsbuf_queue_t *q, - const char *caption, const char *code, ...); - -void ajax_transport_build_mapper_state(char *buf, size_t siz, - th_transport_t *t, int mapped); - - -#endif /* AJAXUI_H_ */ diff --git a/ajaxui/ajaxui_channels.c b/ajaxui/ajaxui_channels.c deleted file mode 100644 index 4e1b9dcc..00000000 --- a/ajaxui/ajaxui_channels.c +++ /dev/null @@ -1,243 +0,0 @@ -/* - * tvheadend, AJAX / HTML user interface - * Copyright (C) 2008 Andreas Öman - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include -#include -#include - -#include -#include -#include -#include -#include -#include - - -#include "tvhead.h" -#include "http.h" -#include "ajaxui.h" -#include "channels.h" -#include "epg.h" - -static void -ajax_channelgroupmenu_content(htsbuf_queue_t *tq, int current) -{ - channel_group_t *tcg; - - htsbuf_qprintf(tq, "
    "); - - TAILQ_FOREACH(tcg, &all_channel_groups, tcg_global_link) { - if(tcg->tcg_hidden) - continue; - - if(current < 1) - current = tcg->tcg_tag; - - htsbuf_qprintf(tq, - "" - "%s" - "", - current == tcg->tcg_tag ? " style=\"font-weight:bold;\"" : "", - tcg->tcg_tag, tcg->tcg_name); - } - htsbuf_qprintf(tq, "
"); -} - - -/* - * Channelgroup menu bar - */ -static int -ajax_channelgroup_menu(http_connection_t *hc, http_reply_t *hr, - const char *remain, void *opaque) -{ - htsbuf_queue_t *tq = &hr->hr_q; - - if(remain == NULL) - return HTTP_STATUS_NOT_FOUND; - - ajax_channelgroupmenu_content(tq, atoi(remain)); - http_output_html(hc, hr); - return 0; -} - - -static void -ajax_output_event(htsbuf_queue_t *tq, event_t *e, int flags, int color) -{ - struct tm a, b; - time_t stop; - - htsbuf_qprintf(tq, "
", - color ? "style=\"background: #fff\" " : ""); - - localtime_r(&e->e_start, &a); - stop = e->e_start + e->e_duration; - localtime_r(&stop, &b); - - htsbuf_qprintf(tq, - "
" - "%02d:%02d-%02d:%02d" - "
", - a.tm_hour, a.tm_min, b.tm_hour, b.tm_min); - - htsbuf_qprintf(tq, - "
" - "%s" - "
", - e->e_title); - - htsbuf_qprintf(tq, "
"); -} - - -static void -ajax_list_events(htsbuf_queue_t *tq, channel_t *ch, int lines) -{ - event_t *e; - int i; - - e = epg_event_find_current_or_upcoming(ch); - - for(i = 0; i < 3 && e != NULL; i++) { - ajax_output_event(tq, e, 0, !(i & 1)); - e = TAILQ_NEXT(e, e_channel_link); - } -} - - -/* - * Display a list of all channels within the given group - * - * Group is given by 'tag' as an ASCII string in remain - */ -static int -ajax_channel_tab(http_connection_t *hc, http_reply_t *hr, - const char *remain, void *opaque) -{ - - htsbuf_queue_t *tq = &hr->hr_q; - channel_t *ch; - channel_group_t *tcg; - char dispname[20]; - struct sockaddr_in *si; - int nchs = 0; - - if(remain == NULL || (tcg = channel_group_by_tag(atoi(remain))) == NULL) - return HTTP_STATUS_NOT_FOUND; - - TAILQ_FOREACH(ch, &tcg->tcg_channels, ch_group_link) { - if(LIST_FIRST(&ch->ch_transports) == NULL) - continue; - - nchs++; - - htsbuf_qprintf(tq, "
"); - - snprintf(dispname, sizeof(dispname), "%s", ch->ch_name); - strcpy(dispname + sizeof(dispname) - 4, "..."); - - ajax_box_begin(tq, AJAX_BOX_SIDEBOX, NULL, NULL, dispname); - - /* inner */ - - htsbuf_qprintf(tq, - "
"); - - htsbuf_qprintf(tq, - "
"); - - if(ch->ch_icon != NULL) { - htsbuf_qprintf(tq, "", - ch->ch_icon); - } - - htsbuf_qprintf(tq, "
"); - - htsbuf_qprintf(tq, "
"); - - si = (struct sockaddr_in *)&hc->hc_tcp_session.tcp_self_addr; - - htsbuf_qprintf(tq, - "Stream", - inet_ntoa(si->sin_addr), ntohs(si->sin_port), - ch->ch_sname); - - htsbuf_qprintf(tq, "
"); - htsbuf_qprintf(tq, "
"); - - - htsbuf_qprintf(tq, "
", ch->ch_tag); - ajax_list_events(tq, ch, 3); - htsbuf_qprintf(tq, "
"); - - ajax_box_end(tq, AJAX_BOX_SIDEBOX); - htsbuf_qprintf(tq, "
"); - } - - if(nchs == 0) - htsbuf_qprintf(tq, "
" - "No channels in this group
"); - - http_output_html(hc, hr); - return 0; -} - - - - - -/* - * Channel (group)s AJAX page - * - * This is the top level menu for this c-file - */ -int -ajax_channelgroup_tab(http_connection_t *hc, http_reply_t *hr) -{ - htsbuf_queue_t *tq = &hr->hr_q; - - ajax_box_begin(tq, AJAX_BOX_FILLED, "channelgroupmenu", NULL, NULL); - ajax_box_end(tq, AJAX_BOX_FILLED); - - htsbuf_qprintf(tq, "
"); - - htsbuf_qprintf(tq, - ""); - - http_output_html(hc, hr); - return 0; -} - - - -/** - * - */ -void -ajax_channels_init(void) -{ - http_path_add("/ajax/channelgroupmenu", NULL, ajax_channelgroup_menu, - ACCESS_WEB_INTERFACE); - http_path_add("/ajax/channelgrouptab", NULL, ajax_channel_tab, - ACCESS_WEB_INTERFACE); - -} diff --git a/ajaxui/ajaxui_config.c b/ajaxui/ajaxui_config.c deleted file mode 100644 index 9397bf72..00000000 --- a/ajaxui/ajaxui_config.c +++ /dev/null @@ -1,146 +0,0 @@ -/* - * tvheadend, AJAX / HTML user interface - * Copyright (C) 2008 Andreas Öman - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include -#include -#include -#include -#include -#include - -#include "tvhead.h" -#include "http.h" -#include "ajaxui.h" -#include "channels.h" - - -#define AJAX_CONFIG_TAB_CHANNELS 0 -#define AJAX_CONFIG_TAB_DVB 1 -#define AJAX_CONFIG_TAB_XMLTV 2 -#define AJAX_CONFIG_TAB_CWC 3 -#define AJAX_CONFIG_TAB_ACCESS 4 -#define AJAX_CONFIG_TABS 5 - -const char *ajax_config_tabnames[] = { - [AJAX_CONFIG_TAB_CHANNELS] = "Channels & Groups", - [AJAX_CONFIG_TAB_DVB] = "DVB adapters", - [AJAX_CONFIG_TAB_XMLTV] = "XML-TV", - [AJAX_CONFIG_TAB_CWC] = "Code-word Client", - [AJAX_CONFIG_TAB_ACCESS] = "Access control", -}; - - -/* - * Titlebar AJAX page - */ -static int -ajax_config_menu(http_connection_t *hc, http_reply_t *hr, - const char *remain, void *opaque) -{ - htsbuf_queue_t *tq = &hr->hr_q; - - if(remain == NULL) - return HTTP_STATUS_NOT_FOUND; - - ajax_menu_bar_from_array(tq, "config", - ajax_config_tabnames, AJAX_CONFIG_TABS, - atoi(remain)); - http_output_html(hc, hr); - return 0; -} - -/* - * Tab AJAX page - * - * Switch to different tabs - */ -static int -ajax_config_dispatch(http_connection_t *hc, http_reply_t *hr, - const char *remain, void *opaque) -{ - int tab; - - if(remain == NULL) - return HTTP_STATUS_NOT_FOUND; - - tab = atoi(remain); - - switch(tab) { - case AJAX_CONFIG_TAB_CHANNELS: - return ajax_config_channels_tab(hc, hr); - case AJAX_CONFIG_TAB_DVB: - return ajax_config_dvb_tab(hc, hr); - case AJAX_CONFIG_TAB_XMLTV: - return ajax_config_xmltv_tab(hc, hr); - case AJAX_CONFIG_TAB_CWC: - return ajax_config_cwc_tab(hc, hr); - case AJAX_CONFIG_TAB_ACCESS: - return ajax_config_access_tab(hc, hr); - - default: - return HTTP_STATUS_NOT_FOUND; - } - return 0; -} - - - - -/* - * Config root menu AJAX page - * - * This is the top level menu for this c-file - */ -int -ajax_config_tab(http_connection_t *hc, http_reply_t *hr) -{ - htsbuf_queue_t *tq = &hr->hr_q; - - ajax_box_begin(tq, AJAX_BOX_FILLED, "configmenu", NULL, NULL); - ajax_box_end(tq, AJAX_BOX_FILLED); - - htsbuf_qprintf(tq, "
"); - - htsbuf_qprintf(tq, - ""); - - http_output_html(hc, hr); - return 0; -} - - - -/** - * - */ -void -ajax_config_init(void) -{ - http_path_add("/ajax/configmenu", NULL, ajax_config_menu, - AJAX_ACCESS_CONFIG); - http_path_add("/ajax/configtab", NULL, ajax_config_dispatch, - AJAX_ACCESS_CONFIG); - - ajax_config_channels_init(); - ajax_config_dvb_init(); - ajax_config_xmltv_init(); - ajax_config_access_init(); - ajax_config_cwc_init(); -} diff --git a/ajaxui/ajaxui_config_access.c b/ajaxui/ajaxui_config_access.c deleted file mode 100644 index f908b159..00000000 --- a/ajaxui/ajaxui_config_access.c +++ /dev/null @@ -1,322 +0,0 @@ -/* - * tvheadend, AJAX / HTML user interface - * Copyright (C) 2008 Andreas Öman - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#define _GNU_SOURCE - -#include -#include -#include -#include -#include -#include - -#include "tvhead.h" -#include "http.h" -#include "ajaxui.h" -#include "channels.h" -#include "psi.h" -#include "transports.h" - -#include "ajaxui_mailbox.h" - - -static struct strtab accesstypetab[] = { - { "stream", ACCESS_STREAMING }, - { "rec", ACCESS_RECORDER_VIEW }, - { "recedit", ACCESS_RECORDER_CHANGE }, - { "admin", ACCESS_ADMIN }, - { "webui", ACCESS_WEB_INTERFACE }, - { "access", ACCESS_ADMIN_ACCESS }, -}; - - -/** - * Access configuration - */ -int -ajax_config_access_tab(http_connection_t *hc, http_reply_t *hr) -{ - htsbuf_queue_t *tq = &hr->hr_q; - - if(access_verify(hc->hc_username, hc->hc_password, - (struct sockaddr *)&hc->hc_tcp_session.tcp_peer_addr, - AJAX_ACCESS_ACCESSCTRL)) - return HTTP_STATUS_UNAUTHORIZED; - - htsbuf_qprintf(tq, "
"); - - ajax_box_begin(tq, AJAX_BOX_SIDEBOX, NULL, NULL, "Access control"); - - htsbuf_qprintf(tq, "
"); - - ajax_js(tq, - "new Ajax.Updater('alist', '/ajax/accesslist', " - "{method: 'get', evalScripts: true});"); - - htsbuf_qprintf(tq, "
"); - - htsbuf_qprintf(tq, - "
" - "
" - "" - "" - "
" - "
"); - - htsbuf_qprintf(tq, "
\r\n"); - - ajax_box_end(tq, AJAX_BOX_SIDEBOX); - - htsbuf_qprintf(tq, "
"); - http_output_html(hc, hr); - return 0; -} - -static void -ajax_access_checkbox(ajax_table_t *ta, access_entry_t *ae, int mask, - const char *n) -{ - ajax_table_cell(ta, NULL, - "", - ae->ae_rights & mask ? "checked " : "", - ae->ae_tally, n); -} - - -/** - * - */ -static int -ajax_accesslist(http_connection_t *hc, http_reply_t *hr, - const char *remain, void *opaque) -{ - htsbuf_queue_t *tq = &hr->hr_q; - access_entry_t *ae; - ajax_table_t ta; - char id[100]; - - ajax_table_top(&ta, hc, tq, - (const char *[]){"User or Prefix", - "Password", - "Streaming", - "Recorder", - "Recorder edit", - "Admin", - "Web UI", - "Accessedit", - "", - NULL}, - (int[]){2, 2, 1, 1, 1, 1, 1, 1, 1, 1}); - - TAILQ_FOREACH(ae, &access_entries, ae_link) { - snprintf(id, sizeof(id), "%d", ae->ae_tally); - ajax_table_row_start(&ta, id); - - ajax_table_cell(&ta, NULL, "%s", ae->ae_title); - if(access_is_prefix(ae)) { - ajax_table_cell(&ta, NULL, "%s", "n/a"); - } else { - ajax_table_cell(&ta, "password", - "" - "%s", - ae->ae_tally, ae->ae_tally, - ae->ae_password != NULL ? "Change..." : "Set..."); - } - - ajax_access_checkbox(&ta, ae, ACCESS_STREAMING, "stream"); - ajax_access_checkbox(&ta, ae, ACCESS_RECORDER_VIEW, "rec"); - ajax_access_checkbox(&ta, ae, ACCESS_RECORDER_CHANGE, "recedit"); - - ajax_access_checkbox(&ta, ae, ACCESS_ADMIN, "admin"); - ajax_access_checkbox(&ta, ae, ACCESS_WEB_INTERFACE, "webui"); - ajax_access_checkbox(&ta, ae, ACCESS_ADMIN_ACCESS, "access"); - - - ajax_table_cell(&ta, NULL, - "" - "Delete...", - ae->ae_tally, ae->ae_title); - } - - ajax_table_bottom(&ta); - http_output_html(hc, hr); - return 0; -} - - -/** - * - */ -static int -ajax_accessadd(http_connection_t *hc, http_reply_t *hr, - const char *remain, void *opaque) -{ - htsbuf_queue_t *tq = &hr->hr_q; - access_entry_t *ae; - const char *t; - - if((t = http_arg_get(&hc->hc_req_args, "name")) == NULL) - return HTTP_STATUS_BAD_REQUEST; - - htsbuf_qprintf(tq, "$('newuser').clear();\r\n"); - - if(t == NULL || strlen(t) < 1 || strchr(t, '\'') || strchr(t, '"')) { - htsbuf_qprintf(tq, "alert('Invalid username');\r\n"); - } else { - ae = access_add(t); - if(ae == NULL) { - htsbuf_qprintf(tq, "alert('Invalid prefix');\r\n"); - } else { - htsbuf_qprintf(tq, - "new Ajax.Updater('alist', '/ajax/accesslist', " - "{method: 'get', evalScripts: true});\r\n"); - } - } - - http_output(hc, hr, "text/javascript; charset=UTF8", NULL, 0); - - return 0; -} - -/** - * - */ -static int -ajax_accesschange(http_connection_t *hc, http_reply_t *hr, - const char *remain, void *opaque) -{ - // htsbuf_queue_t *tq = &hr->hr_tq; - access_entry_t *ae; - const char *e, *c; - int bit; - - if(remain == NULL || (ae = access_by_id(atoi(remain))) == NULL) - return HTTP_STATUS_BAD_REQUEST; - - if((e = http_arg_get(&hc->hc_req_args, "entry")) == NULL) - return HTTP_STATUS_BAD_REQUEST; - - if((bit = str2val(e, accesstypetab)) < 0) - return HTTP_STATUS_BAD_REQUEST; - - if((c = http_arg_get(&hc->hc_req_args, "checked")) == NULL) - return HTTP_STATUS_BAD_REQUEST; - - if(!strcasecmp(c, "false")) { - ae->ae_rights &= ~bit; - } else if(!strcasecmp(c, "true")) { - ae->ae_rights |= bit; - } else { - return HTTP_STATUS_BAD_REQUEST; - } - - access_save(); - - http_output(hc, hr, "text/javascript; charset=UTF8", NULL, 0); - return 0; -} - - -/** - * - */ -static int -ajax_accessdel(http_connection_t *hc, http_reply_t *hr, - const char *remain, void *opaque) -{ - htsbuf_queue_t *tq = &hr->hr_q; - access_entry_t *ae; - const char *e; - - if((e = http_arg_get(&hc->hc_req_args, "id")) == NULL) - return HTTP_STATUS_BAD_REQUEST; - - if((ae = access_by_id(atoi(e))) == NULL) - return HTTP_STATUS_BAD_REQUEST; - - access_delete(ae); - - htsbuf_qprintf(tq, - "new Ajax.Updater('alist', '/ajax/accesslist', " - "{method: 'get', evalScripts: true});\r\n"); - - http_output(hc, hr, "text/javascript; charset=UTF8", NULL, 0); - return 0; -} - - - -/** - * - */ -static int -ajax_accesssetpw(http_connection_t *hc, http_reply_t *hr, - const char *remain, void *opaque) -{ - htsbuf_queue_t *tq = &hr->hr_q; - access_entry_t *ae; - const char *e; - - if(remain == NULL || (ae = access_by_id(atoi(remain))) == NULL) - return HTTP_STATUS_BAD_REQUEST; - - if((e = http_arg_get(&hc->hc_req_args, "value")) == NULL) - return HTTP_STATUS_BAD_REQUEST; - - free(ae->ae_password); - ae->ae_password = strdup(e); - - access_save(); - - htsbuf_qprintf(tq, - "$('password_%d').innerHTML= '" - "" - "%s';", - ae->ae_tally, ae->ae_tally, ae->ae_tally, "Change..."); - - http_output(hc, hr, "text/javascript; charset=UTF8", NULL, 0); - return 0; -} - - -/** - * - */ -void -ajax_config_access_init(void) -{ - http_path_add("/ajax/accesslist" , NULL, ajax_accesslist, - AJAX_ACCESS_ACCESSCTRL); - http_path_add("/ajax/accessadd" , NULL, ajax_accessadd, - AJAX_ACCESS_ACCESSCTRL); - http_path_add("/ajax/accesschange" , NULL, ajax_accesschange, - AJAX_ACCESS_ACCESSCTRL); - http_path_add("/ajax/accessdel" , NULL, ajax_accessdel, - AJAX_ACCESS_ACCESSCTRL); - http_path_add("/ajax/accesssetpw" , NULL, ajax_accesssetpw, - AJAX_ACCESS_ACCESSCTRL); -} diff --git a/ajaxui/ajaxui_config_channels.c b/ajaxui/ajaxui_config_channels.c deleted file mode 100644 index 309c63b2..00000000 --- a/ajaxui/ajaxui_config_channels.c +++ /dev/null @@ -1,755 +0,0 @@ -/* - * tvheadend, AJAX / HTML user interface - * Copyright (C) 2008 Andreas Öman - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include -#include -#include -#include -#include -#include - -#include "tvhead.h" -#include "http.h" -#include "ajaxui.h" -#include "channels.h" - - - -/** - * Render a channel group widget - */ -static void -ajax_chgroup_build(htsbuf_queue_t *tq, channel_group_t *tcg) -{ - htsbuf_qprintf(tq, "
  • ", tcg->tcg_tag); - - ajax_box_begin(tq, AJAX_BOX_BORDER, NULL, NULL, NULL); - - htsbuf_qprintf(tq, "
    "); - - htsbuf_qprintf(tq, - "
    " - "" - "%s
    ", - tcg->tcg_tag, tcg->tcg_name); - - - if(tcg != defgroup) { - htsbuf_qprintf(tq, - "
    " - "Delete
    ", - tcg->tcg_tag, tcg->tcg_name); - } - - - htsbuf_qprintf(tq, "
    "); - ajax_box_end(tq, AJAX_BOX_BORDER); - htsbuf_qprintf(tq, "
  • "); -} - -/** - * Update order of channel groups - */ -static int -ajax_chgroup_updateorder(http_connection_t *hc, http_reply_t *hr, - const char *remain, void *opaque) -{ - channel_group_t *tcg; - htsbuf_queue_t *tq = &hr->hr_q; - http_arg_t *ra; - - TAILQ_FOREACH(ra, &hc->hc_req_args, link) { - if(strcmp(ra->key, "channelgrouplist[]") || - (tcg = channel_group_by_tag(atoi(ra->val))) == NULL) - continue; - - TAILQ_REMOVE(&all_channel_groups, tcg, tcg_global_link); - TAILQ_INSERT_TAIL(&all_channel_groups, tcg, tcg_global_link); - } - - channel_group_settings_write(); - - htsbuf_qprintf(tq, "Updated on server"); - ajax_js(tq, "Effect.Fade('updatedok')"); - http_output_html(hc, hr); - return 0; -} - - - -/** - * Add a new channel group - */ -static int -ajax_chgroup_add(http_connection_t *hc, http_reply_t *hr, - const char *remain, void *opaque) -{ - channel_group_t *tcg; - htsbuf_queue_t *tq = &hr->hr_q; - const char *name; - - if((name = http_arg_get(&hc->hc_req_args, "name")) != NULL) { - - TAILQ_FOREACH(tcg, &all_channel_groups, tcg_global_link) - if(!strcmp(name, tcg->tcg_name)) - break; - - if(tcg == NULL) { - tcg = channel_group_find(name, 1); - - ajax_chgroup_build(tq, tcg); - - /* We must recreate the Sortable object */ - - ajax_js(tq, "Sortable.destroy(\"channelgrouplist\")"); - - ajax_js(tq, "Sortable.create(\"channelgrouplist\", " - "{onUpdate:function(){updatelistonserver(" - "'channelgrouplist', " - "'/ajax/chgroup_updateorder', " - "'list-info'" - ")}});"); - } - } - http_output_html(hc, hr); - return 0; -} - - - -/** - * Delete a channel group - */ -static int -ajax_chgroup_del(http_connection_t *hc, http_reply_t *hr, - const char *remain, void *opaque) -{ - channel_group_t *tcg; - htsbuf_queue_t *tq = &hr->hr_q; - const char *id; - - if((id = http_arg_get(&hc->hc_req_args, "id")) == NULL) - return HTTP_STATUS_BAD_REQUEST; - - if((tcg = channel_group_by_tag(atoi(id))) == NULL) - return HTTP_STATUS_BAD_REQUEST; - - htsbuf_qprintf(tq, "$('chgrp_%d').remove();", tcg->tcg_tag); - http_output(hc, hr, "text/javascript; charset=UTF-8", NULL, 0); - - channel_group_destroy(tcg); - return 0; -} - - - -/** - * Channel group & channel configuration - */ -int -ajax_config_channels_tab(http_connection_t *hc, http_reply_t *hr) -{ - htsbuf_queue_t *tq = &hr->hr_q; - channel_group_t *tcg; - - htsbuf_qprintf(tq, "
    "); - - ajax_box_begin(tq, AJAX_BOX_SIDEBOX, "channelgroups", - NULL, "Channel groups"); - - htsbuf_qprintf(tq, "
    "); - - htsbuf_qprintf(tq, "
      "); - - TAILQ_FOREACH(tcg, &all_channel_groups, tcg_global_link) { - if(tcg->tcg_hidden) - continue; - ajax_chgroup_build(tq, tcg); - } - - htsbuf_qprintf(tq, "
    "); - - ajax_js(tq, "Sortable.create(\"channelgrouplist\", " - "{onUpdate:function(){updatelistonserver(" - "'channelgrouplist', " - "'/ajax/chgroup_updateorder', " - "'list-info'" - ")}});"); - - /** - * Add new group - */ - - htsbuf_qprintf(tq, "
    "); - - ajax_box_begin(tq, AJAX_BOX_BORDER, NULL, NULL, NULL); - - htsbuf_qprintf(tq, - "
    " - "
    " - "" - "
    " - "
    " - "" - "
    "); - - ajax_box_end(tq, AJAX_BOX_BORDER); - - ajax_box_end(tq, AJAX_BOX_SIDEBOX); - htsbuf_qprintf(tq, "
    "); - - htsbuf_qprintf(tq, - "
    "); - - htsbuf_qprintf(tq, - "
    "); - - http_output_html(hc, hr); - return 0; -} - -/** - * Display all channels within the group - */ -static int -ajax_chgroup_editor(http_connection_t *hc, http_reply_t *hr, - const char *remain, void *opaque) -{ - htsbuf_queue_t *tq = &hr->hr_q; - channel_t *ch; - channel_group_t *tcg, *tcg2; - th_transport_t *t; - char buf[10]; - int nsources; - ajax_table_t ta; - - if(remain == NULL || (tcg = channel_group_by_tag(atoi(remain))) == NULL) - return HTTP_STATUS_BAD_REQUEST; - - htsbuf_qprintf(tq, "\r\n"); - - - ajax_box_begin(tq, AJAX_BOX_SIDEBOX, NULL, NULL, tcg->tcg_name); - - ajax_table_top(&ta, hc, tq, (const char *[]) - {"Channelname", "Sources", "", NULL}, - (int[]){8,2,1}); - - TAILQ_FOREACH(ch, &tcg->tcg_channels, ch_group_link) { - snprintf(buf, sizeof(buf), "%d", ch->ch_tag); - ajax_table_row_start(&ta, buf); - - nsources = 0; - - LIST_FOREACH(t, &ch->ch_transports, tht_ch_link) - nsources++; - - ajax_table_cell(&ta, NULL, - "%s", ch->ch_tag, ch->ch_name); - - ajax_table_cell(&ta, NULL, "%d", nsources); - ajax_table_cell_checkbox(&ta); - } - ajax_table_bottom(&ta); - - htsbuf_qprintf(tq, "
    \r\n"); - htsbuf_qprintf(tq, "
    "); - - ajax_button(tq, "Select all", "select_all()"); - ajax_button(tq, "Select none", "select_none()"); - ajax_button(tq, "Invert selection", "select_invert()"); - ajax_button(tq, "Select channels with sources", "select_sources()"); - htsbuf_qprintf(tq, "
    \r\n"); - - htsbuf_qprintf(tq, "
    \r\n"); - - htsbuf_qprintf(tq, "
    "); - - ajax_button(tq, - "Delete all selected...", - "select_do('delete', '%d', 0, true);", tcg->tcg_tag); - - htsbuf_qprintf(tq, - "
    "); - htsbuf_qprintf(tq, ""); - htsbuf_qprintf(tq, ""); - ajax_box_end(tq, AJAX_BOX_SIDEBOX); - - - http_output_html(hc, hr); - return 0; -} - - -/** - * - */ -static struct strtab sourcetypetab[] = { - { "DVB", TRANSPORT_DVB }, - { "V4L", TRANSPORT_V4L }, - { "IPTV", TRANSPORT_IPTV }, - { "AVgen", TRANSPORT_AVGEN }, - { "File", TRANSPORT_STREAMEDFILE }, -}; - - -static struct strtab cdlongname[] = { - { "None", COMMERCIAL_DETECT_NONE }, - { "Swedish TV4 Teletext", COMMERCIAL_DETECT_TTP192 }, -}; - -/** - * Display all channels within the group - */ -static int -ajax_cheditor(http_connection_t *hc, http_reply_t *hr, - const char *remain, void *opaque) -{ - htsbuf_queue_t *tq = &hr->hr_q; - channel_t *ch, *ch2; - channel_group_t *chg; - th_transport_t *t; - const char *s; - int i; - - if(remain == NULL || (ch = channel_by_tag(atoi(remain))) == NULL) - return HTTP_STATUS_BAD_REQUEST; - - ajax_box_begin(tq, AJAX_BOX_SIDEBOX, NULL, NULL, ch->ch_name); - - if(ch->ch_icon != NULL) { - htsbuf_qprintf(tq, - "
    " - "
    ", ch->ch_icon); - } - - htsbuf_qprintf(tq, "
    Sources:
    "); - - LIST_FOREACH(t, &ch->ch_transports, tht_ch_link) { - ajax_box_begin(tq, AJAX_BOX_BORDER, NULL, NULL, NULL); - htsbuf_qprintf(tq, "
    "); - htsbuf_qprintf(tq, "
    %s
    ", - val2str(t->tht_type, sourcetypetab) ?: "???"); - htsbuf_qprintf(tq, "
    \"%s\"%s
    ", - t->tht_svcname, t->tht_scrambled ? " - (scrambled)" : ""); - s = t->tht_sourcename ? t->tht_sourcename(t) : NULL; - - htsbuf_qprintf(tq, "
    "); - - htsbuf_qprintf(tq, - "
    " - "" - "
    ", t->tht_disabled ? "" : "checked ", - t->tht_identifier); - - if(s != NULL) - htsbuf_qprintf(tq, "
    %s
    ", - s); - - htsbuf_qprintf(tq, "
    "); - - ajax_box_end(tq, AJAX_BOX_BORDER); - } - - htsbuf_qprintf(tq, "
    \r\n"); - - htsbuf_qprintf(tq, "
    "); - - htsbuf_qprintf(tq, - "", - ch->ch_tag, ch->ch_name); - - htsbuf_qprintf(tq, - "", - ch->ch_tag, ch->ch_name); - - htsbuf_qprintf(tq, - ""); - htsbuf_qprintf(tq, "
    "); - htsbuf_qprintf(tq, "
    \r\n"); - - htsbuf_qprintf(tq, - "
    " - "Commercial detection:
    " - "
    " - "
    "); - htsbuf_qprintf(tq, ""); - - - ajax_box_end(tq, AJAX_BOX_SIDEBOX); - http_output_html(hc, hr); - return 0; -} - -/** - * Change group for channel(s) - */ -static int -ajax_changegroup(http_connection_t *hc, http_reply_t *hr, - const char *remain, void *opaque) -{ - htsbuf_queue_t *tq = &hr->hr_q; - channel_t *ch; - channel_group_t *tcg; - http_arg_t *ra; - const char *s; - const char *curgrp; - - if((s = http_arg_get(&hc->hc_req_args, "arg1")) == NULL) - return HTTP_STATUS_BAD_REQUEST; - - if((curgrp = http_arg_get(&hc->hc_req_args, "arg2")) == NULL) - return HTTP_STATUS_BAD_REQUEST; - - tcg = channel_group_by_tag(atoi(s)); - if(tcg == NULL) - return HTTP_STATUS_BAD_REQUEST; - - TAILQ_FOREACH(ra, &hc->hc_req_args, link) { - if(strcmp(ra->val, "selected")) - continue; - - if((ch = channel_by_tag(atoi(ra->key))) != NULL) - channel_set_group(ch, tcg); - } - - htsbuf_qprintf(tq, - "$('cheditortab').innerHTML=''; " - "new Ajax.Updater('groupeditortab', " - "'/ajax/chgroup_editor/%s', " - "{method: 'get', evalScripts: true});", curgrp); - - http_output(hc, hr, "text/javascript; charset=UTF-8", NULL, 0); - return 0; -} - -/** - * Change commercial detection type for channel(s) - */ -static int -ajax_chsetcomdetect(http_connection_t *hc, http_reply_t *hr, - const char *remain, void *opaque) -{ - channel_t *ch; - const char *s; - - if(remain == NULL || (ch = channel_by_tag(atoi(remain))) == NULL) - return HTTP_STATUS_BAD_REQUEST; - - if((s = http_arg_get(&hc->hc_req_args, "how")) == NULL) - return HTTP_STATUS_BAD_REQUEST; - - ch->ch_commercial_detection = atoi(s); - - channel_settings_write(ch); - http_output(hc, hr, "text/javascript; charset=UTF-8", NULL, 0); - return 0; -} - - -/** - * Rename a channel - */ -static int -ajax_chrename(http_connection_t *hc, http_reply_t *hr, - const char *remain, void *opaque) -{ - htsbuf_queue_t *tq = &hr->hr_q; - channel_t *ch; - const char *s; - - if(remain == NULL || (ch = channel_by_tag(atoi(remain))) == NULL) - return HTTP_STATUS_BAD_REQUEST; - - if((s = http_arg_get(&hc->hc_req_args, "newname")) == NULL) - return HTTP_STATUS_BAD_REQUEST; - - if(channel_rename(ch, s)) { - htsbuf_qprintf(tq, "alert('Channel already exist');"); - } else { - htsbuf_qprintf(tq, - "new Ajax.Updater('groupeditortab', " - "'/ajax/chgroup_editor/%d', " - "{method: 'get', evalScripts: true});\r\n", - ch->ch_group->tcg_tag); - - htsbuf_qprintf(tq, - "new Ajax.Updater('cheditortab', " - "'/ajax/cheditor/%d', " - "{method: 'get', evalScripts: true});\r\n", - ch->ch_tag); - } - - http_output(hc, hr, "text/javascript; charset=UTF-8", NULL, 0); - return 0; -} - - -/** - * Delete channel - */ -static int -ajax_chdelete(http_connection_t *hc, http_reply_t *hr, - const char *remain, void *opaque) -{ - htsbuf_queue_t *tq = &hr->hr_q; - channel_t *ch; - channel_group_t *tcg; - - if(remain == NULL || (ch = channel_by_tag(atoi(remain))) == NULL) - return HTTP_STATUS_BAD_REQUEST; - - tcg = ch->ch_group; - - channel_delete(ch); - - htsbuf_qprintf(tq, - "new Ajax.Updater('groupeditortab', " - "'/ajax/chgroup_editor/%d', " - "{method: 'get', evalScripts: true});\r\n", - tcg->tcg_tag); - - htsbuf_qprintf(tq, "$('cheditortab').innerHTML='';\r\n"); - - http_output(hc, hr, "text/javascript; charset=UTF-8", NULL, 0); - return 0; -} - -/** - * Merge channel - */ -static int -ajax_chmerge(http_connection_t *hc, http_reply_t *hr, - const char *remain, void *opaque) -{ - htsbuf_queue_t *tq = &hr->hr_q; - channel_t *src, *dst; - channel_group_t *tcg; - const char *s; - - if(remain == NULL || (src = channel_by_tag(atoi(remain))) == NULL) - return HTTP_STATUS_NOT_FOUND; - - if((s = http_arg_get(&hc->hc_req_args, "dst")) == NULL) - return HTTP_STATUS_BAD_REQUEST; - - if((dst = channel_by_tag(atoi(s))) == NULL) - return HTTP_STATUS_BAD_REQUEST; - - tcg = src->ch_group; - channel_merge(dst, src); - - htsbuf_qprintf(tq, - "new Ajax.Updater('groupeditortab', " - "'/ajax/chgroup_editor/%d', " - "{method: 'get', evalScripts: true});\r\n", - tcg->tcg_tag); - - htsbuf_qprintf(tq, "$('cheditortab').innerHTML='';\r\n"); - - http_output(hc, hr, "text/javascript; charset=UTF-8", NULL, 0); - return 0; -} - -/** - * Change group for channel(s) - */ -static int -ajax_chdeletemulti(http_connection_t *hc, http_reply_t *hr, - const char *remain, void *opaque) -{ - htsbuf_queue_t *tq = &hr->hr_q; - channel_t *ch; - http_arg_t *ra; - const char *curgrp; - - if((curgrp = http_arg_get(&hc->hc_req_args, "arg1")) == NULL) - return HTTP_STATUS_BAD_REQUEST; - - TAILQ_FOREACH(ra, &hc->hc_req_args, link) { - if(strcmp(ra->val, "selected")) - continue; - - if((ch = channel_by_tag(atoi(ra->key))) != NULL) - channel_delete(ch); - } - - htsbuf_qprintf(tq, - "$('cheditortab').innerHTML=''; " - "new Ajax.Updater('groupeditortab', " - "'/ajax/chgroup_editor/%s', " - "{method: 'get', evalScripts: true});", curgrp); - - http_output(hc, hr, "text/javascript; charset=UTF-8", NULL, 0); - return 0; -} - - - -/** - * - */ -void -ajax_config_channels_init(void) -{ - http_path_add("/ajax/chgroup_add" , NULL, ajax_chgroup_add, - AJAX_ACCESS_CONFIG); - http_path_add("/ajax/chgroup_del" , NULL, ajax_chgroup_del, - AJAX_ACCESS_CONFIG); - http_path_add("/ajax/chgroup_updateorder", NULL, ajax_chgroup_updateorder, - AJAX_ACCESS_CONFIG); - http_path_add("/ajax/chgroup_editor", NULL, ajax_chgroup_editor, - AJAX_ACCESS_CONFIG); - http_path_add("/ajax/cheditor", NULL, ajax_cheditor, - AJAX_ACCESS_CONFIG); - http_path_add("/ajax/chop/changegroup", NULL, ajax_changegroup, - AJAX_ACCESS_CONFIG); - http_path_add("/ajax/chsetcomdetect", NULL, ajax_chsetcomdetect, - AJAX_ACCESS_CONFIG); - http_path_add("/ajax/chrename", NULL, ajax_chrename, - AJAX_ACCESS_CONFIG); - http_path_add("/ajax/chdelete", NULL, ajax_chdelete, - AJAX_ACCESS_CONFIG); - http_path_add("/ajax/chmerge", NULL, ajax_chmerge, - AJAX_ACCESS_CONFIG); - http_path_add("/ajax/chop/delete", NULL, ajax_chdeletemulti, - AJAX_ACCESS_CONFIG); - -} diff --git a/ajaxui/ajaxui_config_cwc.c b/ajaxui/ajaxui_config_cwc.c deleted file mode 100644 index 33163d59..00000000 --- a/ajaxui/ajaxui_config_cwc.c +++ /dev/null @@ -1,264 +0,0 @@ -/* - * tvheadend, AJAX / HTML user interface - * Copyright (C) 2008 Andreas Öman - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#define _GNU_SOURCE - -#include -#include -#include -#include -#include -#include - -#include "tvhead.h" -#include "http.h" -#include "ajaxui.h" -#include "cwc.h" -/** - * CWC configuration - */ -int -ajax_config_cwc_tab(http_connection_t *hc, http_reply_t *hr) -{ - htsbuf_queue_t *q = &hr->hr_q; - - ajax_box_begin(q, AJAX_BOX_SIDEBOX, NULL, NULL, "Code-word Client"); - - htsbuf_qprintf(q, "
    "); - - ajax_js(q, - "new Ajax.Updater('cwclist', '/ajax/cwclist', " - "{method: 'get', evalScripts: true});"); - - htsbuf_qprintf(q, "
    "); - - htsbuf_qprintf(q, - "
    " - "
    Hostname:
    " - "
    " - "" - "
    "); - - htsbuf_qprintf(q, - "
    " - "
    Port:
    " - "
    " - "" - "
    "); - - - htsbuf_qprintf(q, - "
    " - "
    Username:
    " - "
    " - "" - "
    "); - - htsbuf_qprintf(q, - "
    " - "
    Password:
    " - "
    " - "" - "
    "); - - htsbuf_qprintf(q, - "
    " - "
    DES-key:
    " - "
    " - "" - "
    "); - - htsbuf_qprintf(q, - "
    " - ""); - - htsbuf_qprintf(q, "
    \r\n"); - - ajax_box_end(q, AJAX_BOX_SIDEBOX); - - htsbuf_qprintf(q, ""); - http_output_html(hc, hr); - return 0; -} - - -/** - * - */ -static int -ajax_cwclist(http_connection_t *hc, http_reply_t *hr, - const char *remain, void *opaque) -{ - htsbuf_queue_t *q = &hr->hr_q; - ajax_table_t ta; - cwc_t *cwc; - char id[20]; - - ajax_table_top(&ta, hc, q, - (const char *[]){"Code-word Server", - "Username", - "Enabled", - "Status", - "", - NULL}, - (int[]){3, 2, 1, 12, 1}); - - TAILQ_FOREACH(cwc, &cwcs, cwc_link) { - snprintf(id, sizeof(id), "cwc_%d", cwc->cwc_id); - ajax_table_row_start(&ta, id); - - ajax_table_cell(&ta, NULL, "%s:%d", - cwc->cwc_tcp_session.tcp_hostname, - cwc->cwc_tcp_session.tcp_port); - - ajax_table_cell(&ta, NULL, "%s", cwc->cwc_username); - - ajax_table_cell(&ta, NULL, - "", - cwc->cwc_tcp_session.tcp_enabled - ? "checked " : "", cwc->cwc_id); - - ajax_table_cell(&ta, "status", cwc_status_to_text(cwc)); - - ajax_table_cell(&ta, NULL, - "" - "Delete...", - cwc->cwc_id, cwc->cwc_tcp_session.tcp_hostname); - } - - ajax_table_bottom(&ta); - http_output_html(hc, hr); - return 0; -} - - -/** - * - */ -static int -ajax_cwcadd(http_connection_t *hc, http_reply_t *hr, - const char *remain, void *opaque) -{ - htsbuf_queue_t *q = &hr->hr_q; - const char *errtxt; - - errtxt = cwc_add(http_arg_get(&hc->hc_req_args, "hostname"), - http_arg_get(&hc->hc_req_args, "port"), - http_arg_get(&hc->hc_req_args, "username"), - http_arg_get(&hc->hc_req_args, "password"), - http_arg_get(&hc->hc_req_args, "deskey"), - "1", 1, 1); - - if(errtxt != NULL) { - htsbuf_qprintf(q, "alert('%s');", errtxt); - } else { - - htsbuf_qprintf(q, "$('hostname').clear();\r\n"); - htsbuf_qprintf(q, "$('port').clear();\r\n"); - htsbuf_qprintf(q, "$('username').clear();\r\n"); - htsbuf_qprintf(q, "$('password').clear();\r\n"); - htsbuf_qprintf(q, "$('deskey').clear();\r\n"); - htsbuf_qprintf(q, - "new Ajax.Updater('cwclist', '/ajax/cwclist', " - "{method: 'get', evalScripts: true});"); - } - http_output(hc, hr, "text/javascript; charset=UTF8", NULL, 0); - - return 0; -} - - -/** - * - */ -static int -ajax_cwcdel(http_connection_t *hc, http_reply_t *hr, - const char *remain, void *opaque) -{ - htsbuf_queue_t *q = &hr->hr_q; - const char *txt; - cwc_t *cwc; - - if((txt = http_arg_get(&hc->hc_req_args, "id")) == NULL) - return HTTP_STATUS_BAD_REQUEST; - - if((cwc = cwc_find(atoi(txt))) == NULL) - return HTTP_STATUS_BAD_REQUEST; - - cwc_delete(cwc); - htsbuf_qprintf(q, - "new Ajax.Updater('cwclist', '/ajax/cwclist', " - "{method: 'get', evalScripts: true});"); - - http_output(hc, hr, "text/javascript; charset=UTF8", NULL, 0); - return 0; -} - -/** - * - */ -static int -ajax_cwcchange(http_connection_t *hc, http_reply_t *hr, - const char *remain, void *opaque) -{ - // htsbuf_queue_t *q = &hr->hr_q; - const char *txt; - cwc_t *cwc; - - if((txt = http_arg_get(&hc->hc_req_args, "id")) == NULL) - return HTTP_STATUS_BAD_REQUEST; - - if((cwc = cwc_find(atoi(txt))) == NULL) - return HTTP_STATUS_BAD_REQUEST; - - if((txt = http_arg_get(&hc->hc_req_args, "checked")) == NULL) - return HTTP_STATUS_BAD_REQUEST; - - cwc_set_enable(cwc, !strcmp(txt, "true")); - http_output(hc, hr, "text/javascript; charset=UTF8", NULL, 0); - return 0; -} - - -/** - * - */ -void -ajax_config_cwc_init(void) -{ - http_path_add("/ajax/cwclist" , NULL, ajax_cwclist, - AJAX_ACCESS_CONFIG); - http_path_add("/ajax/cwcadd" , NULL, ajax_cwcadd, - AJAX_ACCESS_CONFIG); - http_path_add("/ajax/cwcdel" , NULL, ajax_cwcdel, - AJAX_ACCESS_CONFIG); - http_path_add("/ajax/cwcchange" , NULL, ajax_cwcchange, - AJAX_ACCESS_CONFIG); -} diff --git a/ajaxui/ajaxui_config_dvb.c b/ajaxui/ajaxui_config_dvb.c deleted file mode 100644 index 8da3a784..00000000 --- a/ajaxui/ajaxui_config_dvb.c +++ /dev/null @@ -1,1059 +0,0 @@ -/* - * tvheadend, AJAX / HTML user interface - * Copyright (C) 2008 Andreas Öman - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#define _GNU_SOURCE - -#include -#include -#include -#include -#include -#include - -#include - -#include "tvhead.h" -#include "http.h" -#include "ajaxui.h" -#include "channels.h" -#include "dvb.h" -#include "dvb_support.h" -#include "dvb_muxconfig.h" -#include "psi.h" -#include "transports.h" -#include "dispatch.h" - -#include "ajaxui_mailbox.h" - - -static void -add_option(htsbuf_queue_t *tq, int bol, const char *name) -{ - if(bol) - htsbuf_qprintf(tq, "", name); -} - -/** - * - */ -static const char * -nicenum(unsigned int v) -{ - static char buf[4][30]; - static int ptr; - char *x; - ptr = (ptr + 1) & 3; - x = buf[ptr]; - - if(v < 1000) - snprintf(x, 30, "%d", v); - else if(v < 1000000) - snprintf(x, 30, "%d,%03d", v / 1000, v % 1000); - else if(v < 1000000000) - snprintf(x, 30, "%d,%03d,%03d", - v / 1000000, (v % 1000000) / 1000, v % 1000); - else - snprintf(x, 30, "%d,%03d,%03d,%03d", - v / 1000000000, (v % 1000000000) / 1000000, - (v % 1000000) / 1000, v % 1000); - return x; -} - - - -static void -tdmi_displayname(th_dvb_mux_instance_t *tdmi, char *buf, size_t len) -{ - int f = tdmi->tdmi_fe_params.frequency; - - if(tdmi->tdmi_adapter->tda_type == FE_QPSK) { - snprintf(buf, len, "%s kHz %s", nicenum(f), - dvb_polarisation_to_str(tdmi->tdmi_polarisation)); - } else { - snprintf(buf, len, "%s kHz", nicenum(f / 1000)); - } -} - -/* - * Adapter summary - */ -static int -ajax_adaptersummary(http_connection_t *hc, http_reply_t *hr, - const char *remain, void *opaque) -{ - htsbuf_queue_t *tq = &hr->hr_q; - th_dvb_adapter_t *tda; - char dispname[20]; - - if(remain == NULL || (tda = dvb_adapter_find_by_identifier(remain)) == NULL) - return HTTP_STATUS_NOT_FOUND; - - snprintf(dispname, sizeof(dispname), "%s", tda->tda_displayname); - strcpy(dispname + sizeof(dispname) - 4, "..."); - - ajax_box_begin(tq, AJAX_BOX_SIDEBOX, NULL, NULL, dispname); - - htsbuf_qprintf(tq, "
    Device:
    " - "
    %s
    ", - tda->tda_rootpath ?: "Not present"); - htsbuf_qprintf(tq, "
    Type:
    " - "
    %s
    ", - dvb_adaptertype_to_str(tda->tda_type)); - - htsbuf_qprintf(tq, "
    " - "Edit
    ", tda->tda_identifier); - ajax_box_end(tq, AJAX_BOX_SIDEBOX); - - http_output_html(hc, hr); - return 0; -} - - -/** - * DVB configuration - */ -int -ajax_config_dvb_tab(http_connection_t *hc, http_reply_t *hr) -{ - htsbuf_queue_t *tq = &hr->hr_q; - th_dvb_adapter_t *tda; - - htsbuf_qprintf(tq, "
    "); - - if(TAILQ_FIRST(&dvb_adapters) == NULL) { - htsbuf_qprintf(tq, "
    " - "No adapters found
    "); - } - - - TAILQ_FOREACH(tda, &dvb_adapters, tda_global_link) { - - htsbuf_qprintf(tq, "
    ", - tda->tda_identifier); - - ajax_js(tq, "new Ajax.Updater('summary_%s', " - "'/ajax/dvbadaptersummary/%s', {method: 'get'})", - tda->tda_identifier, tda->tda_identifier); - - } - htsbuf_qprintf(tq, "
    "); - htsbuf_qprintf(tq, "
    "); - http_output_html(hc, hr); - return 0; -} - - - -/** - * DVB adapter editor pane - */ -static int -ajax_adaptereditor(http_connection_t *hc, http_reply_t *hr, - const char *remain, void *opaque) -{ - htsbuf_queue_t *tq = &hr->hr_q; - th_dvb_adapter_t *tda, *tda2; - const char *s; - - if(remain == NULL || (tda = dvb_adapter_find_by_identifier(remain)) == NULL) - return HTTP_STATUS_NOT_FOUND; - - ajax_box_begin(tq, AJAX_BOX_FILLED, NULL, NULL, NULL); - - htsbuf_qprintf(tq, - "
    %s
    ", - tda->tda_identifier, tda->tda_displayname); - - ajax_box_end(tq, AJAX_BOX_FILLED); - - /* Type */ - - htsbuf_qprintf(tq, "
    "); - - htsbuf_qprintf(tq, "
    "); - - htsbuf_qprintf(tq, "
    Model:
    " - "
    %s (%s)
    ", - tda->tda_fe_info ? tda->tda_fe_info->name : "", - dvb_adaptertype_to_str(tda->tda_type)); - - - - if(tda->tda_fe_info != NULL) { - - s = tda->tda_type == FE_QPSK ? "kHz" : "Hz"; - htsbuf_qprintf(tq, "
    Freq. Range:
    " - "
    %s - %s %s, in steps of %s %s
    ", - nicenum(tda->tda_fe_info->frequency_min), - nicenum(tda->tda_fe_info->frequency_max), - s, - nicenum(tda->tda_fe_info->frequency_stepsize), - s); - - - if(tda->tda_fe_info->symbol_rate_min) { - htsbuf_qprintf(tq, "
    Symbolrate:
    " - "
    %s - %s Baud
    ", - nicenum(tda->tda_fe_info->symbol_rate_min), - nicenum(tda->tda_fe_info->symbol_rate_max)); - } - /* Capabilities */ - // htsbuf_qprintf(tq, "
    Capabilities:
    "); - } - - htsbuf_qprintf(tq, "
    "); - - htsbuf_qprintf(tq, "
    "); - - htsbuf_qprintf(tq, "
    "); - - htsbuf_qprintf(tq, - "", - tda->tda_identifier, tda->tda_displayname); - - if(tda->tda_rootpath == NULL) { - htsbuf_qprintf(tq, - "", - tda->tda_identifier, tda->tda_displayname); - } - - // htsbuf_qprintf(tq, "
    "); - - /* Clone adapter */ - - // htsbuf_qprintf(tq, "
    "); - htsbuf_qprintf(tq, - "
    "); - htsbuf_qprintf(tq, "
    "); - - htsbuf_qprintf(tq, "
    "); - - htsbuf_qprintf(tq, ""); - - /* Muxes and transports */ - - - htsbuf_qprintf(tq, "
    "); - - ajax_box_begin(tq, AJAX_BOX_SIDEBOX, NULL, NULL, "Multiplexes"); - - htsbuf_qprintf(tq, "
    ", - tda->tda_identifier); - - ajax_js(tq, - "new Ajax.Updater('dvbmuxlist_%s', " - "'/ajax/dvbadaptermuxlist/%s', {method: 'get', evalScripts: true})", - tda->tda_identifier, tda->tda_identifier); - - ajax_box_end(tq, AJAX_BOX_SIDEBOX); - htsbuf_qprintf(tq, "
    "); - - /* Div for displaying services */ - - htsbuf_qprintf(tq, "
    "); - htsbuf_qprintf(tq, "
    "); - - http_output_html(hc, hr); - return 0; -} - - -/** - * DVB adapter add mux - */ -static int -ajax_adapteraddmux(http_connection_t *hc, http_reply_t *hr, - const char *remain, void *opaque) -{ - htsbuf_queue_t *tq = &hr->hr_q; - th_dvb_adapter_t *tda; - int caps; - int fetype; - char params[400]; - int n, type; - const char *networkname; - - if(remain == NULL || (tda = dvb_adapter_find_by_identifier(remain)) == NULL) - return HTTP_STATUS_NOT_FOUND; - - if(tda->tda_fe_info == NULL) - return HTTP_STATUS_BAD_REQUEST; - - caps = tda->tda_fe_info->caps; - fetype = tda->tda_fe_info->type; - - snprintf(params, sizeof(params), "Add new %s mux on \"%s\"", - dvb_adaptertype_to_str(tda->tda_fe_info->type), - tda->tda_displayname); - - ajax_box_begin(tq, AJAX_BOX_SIDEBOX, NULL, NULL, params); - - /* Manual configuration */ - - htsbuf_qprintf(tq, - "
    " - "Manual configuartion
    "); - - htsbuf_qprintf(tq, - "
    " - "
    Frequency (%s):
    " - "
    " - "" - "
    ", - fetype == FE_QPSK ? "kHz" : "Hz"); - - snprintf(params, sizeof(params), - "freq: $F('freq')"); - - /* Symbolrate */ - - if(fetype == FE_QAM || fetype == FE_QPSK) { - - htsbuf_qprintf(tq, - "
    " - "
    Symbolrate:
    " - "
    " - "" - "
    "); - - snprintf(params + strlen(params), sizeof(params) - strlen(params), - ", symrate: $F('symrate')"); - } - - /* Bandwidth */ - - if(fetype == FE_OFDM) { - htsbuf_qprintf(tq, - "
    " - "
    Bandwidth:
    " - "
    "); - - snprintf(params + strlen(params), sizeof(params) - strlen(params), - ", bw: $F('bw')"); - } - - - /* Constellation */ - - - if(fetype == FE_QAM || fetype == FE_OFDM) { - htsbuf_qprintf(tq, - "
    " - "
    Constellation:
    " - "
    "); - - snprintf(params + strlen(params), sizeof(params) - strlen(params), - ", const: $F('const')"); - } - - - /* FEC */ - - if(fetype == FE_QAM || fetype == FE_QPSK) { - htsbuf_qprintf(tq, - "
    " - "
    FEC:
    " - "
    "); - - snprintf(params + strlen(params), sizeof(params) - strlen(params), - ", fec: $F('fec')"); - } - - if(fetype == FE_QPSK) { - htsbuf_qprintf(tq, - "
    " - "
    Polarisation:
    " - "
    "); - - snprintf(params + strlen(params), sizeof(params) - strlen(params), - ", pol: $F('pol')"); - - - } - - - if(fetype == FE_OFDM) { - htsbuf_qprintf(tq, - "
    " - "
    Transmission mode:
    " - "
    "); - - snprintf(params + strlen(params), sizeof(params) - strlen(params), - ", tmode: $F('tmode')"); - - htsbuf_qprintf(tq, - "
    " - "
    Guard interval:
    " - "
    "); - - snprintf(params + strlen(params), sizeof(params) - strlen(params), - ", guard: $F('guard')"); - - - - htsbuf_qprintf(tq, - "
    " - "
    Hierarchy:
    " - "
    "); - - - snprintf(params + strlen(params), sizeof(params) - strlen(params), - ", hier: $F('hier')"); - - - - htsbuf_qprintf(tq, - "
    " - "
    FEC Hi:
    " - "
    "); - - snprintf(params + strlen(params), sizeof(params) - strlen(params), - ", fechi: $F('fechi')"); - - - htsbuf_qprintf(tq, - "
    " - "
    FEC Low:
    " - "
    "); - - snprintf(params + strlen(params), sizeof(params) - strlen(params), - ", feclo: $F('feclo')"); - } - - htsbuf_qprintf(tq, - "
    " - "
    " - "" - "
    ", tda->tda_identifier, params); - - /* - * Preconfigured - */ - - htsbuf_qprintf(tq, - "
    " - "
    " - "Preconfigured network
    "); - - htsbuf_qprintf(tq, - "
    " - "
    "); - - htsbuf_qprintf(tq, - "
    "); - - htsbuf_qprintf(tq, - "
    " - "
    " - "" - "
    ", tda->tda_identifier, params); - - ajax_box_end(tq, AJAX_BOX_SIDEBOX); - - http_output_html(hc, hr); - return 0; -} - -/** - * DVB adapter create mux (come here on POST after addmux query) - */ -static int -ajax_adaptercreatemux(http_connection_t *hc, http_reply_t *hr, - const char *remain, void *opaque) -{ - htsbuf_queue_t *tq; - th_dvb_adapter_t *tda; - const char *v; - - if(remain == NULL || (tda = dvb_adapter_find_by_identifier(remain)) == NULL) - return HTTP_STATUS_NOT_FOUND; - - v = dvb_mux_create_str(tda, - "65535", - NULL, - http_arg_get(&hc->hc_req_args, "freq"), - http_arg_get(&hc->hc_req_args, "symrate"), - http_arg_get(&hc->hc_req_args, "const"), - http_arg_get(&hc->hc_req_args, "fec"), - http_arg_get(&hc->hc_req_args, "fechi"), - http_arg_get(&hc->hc_req_args, "feclo"), - http_arg_get(&hc->hc_req_args, "bw"), - http_arg_get(&hc->hc_req_args, "tmode"), - http_arg_get(&hc->hc_req_args, "guard"), - http_arg_get(&hc->hc_req_args, "hier"), - http_arg_get(&hc->hc_req_args, "pol"), - http_arg_get(&hc->hc_req_args, "port"), 1); - - - tq = &hr->hr_q; - - if(v != NULL) - htsbuf_qprintf(tq, "alert('%s');\r\n", v); - - htsbuf_qprintf(tq, - "$('servicepane').innerHTML='';\r\n"); - - htsbuf_qprintf(tq, - "new Ajax.Updater('dvbmuxlist_%s', " - "'/ajax/dvbadaptermuxlist/%s', " - "{method: 'get', evalScripts: true});\r\n", - tda->tda_identifier, tda->tda_identifier); - - http_output(hc, hr, "text/javascript; charset=UTF8", NULL, 0); - return 0; -} - - -/** - * Return a list of all muxes on the given adapter - */ -static int -ajax_adaptermuxlist(http_connection_t *hc, http_reply_t *hr, - const char *remain, void *opaque) -{ - ajax_table_t ta; - th_dvb_mux_instance_t *tdmi; - htsbuf_queue_t *tq = &hr->hr_q; - th_dvb_adapter_t *tda; - char buf[200]; - int fetype, n, m; - th_transport_t *t; - int nmuxes = 0; - char **selvector; - - if(remain == NULL || (tda = dvb_adapter_find_by_identifier(remain)) == NULL) - return HTTP_STATUS_NOT_FOUND; - - fetype = tda->tda_type; - - /* List of muxes */ - - nmuxes = tda->tda_muxes.entries; - - if(nmuxes == 0) { - htsbuf_qprintf(tq, "
    " - "No muxes configured
    "); - } else { - - - selvector = alloca(sizeof(char *) * (nmuxes + 1)); - n = 0; - RB_FOREACH(tdmi, &tda->tda_muxes, tdmi_adapter_link) - selvector[n++] = tdmi->tdmi_identifier; - selvector[n] = NULL; - - ajax_generate_select_functions(tq, "mux", selvector); - - ajax_table_top(&ta, hc, tq, - (const char *[]) - {"Freq", "Status", "Quality", "State", "Name", "Services", "", NULL}, - (int[]) - {16,12,7,8,16,8,2}); - - RB_FOREACH(tdmi, &tda->tda_muxes, tdmi_adapter_link) { - - tdmi_displayname(tdmi, buf, sizeof(buf)); - - ajax_table_row_start(&ta, tdmi->tdmi_identifier); - - ajax_table_cell(&ta, NULL, - "%s", - tdmi->tdmi_identifier, buf); - - ajax_table_cell(&ta, "status", "%s", dvb_mux_status(tdmi, 0)); - ajax_table_cell(&ta, "qual", "%d%%", - dvb_quality_to_percent(tdmi->tdmi_quality)); - ajax_table_cell(&ta, "state", "%s", dvb_mux_state(tdmi)); - ajax_table_cell(&ta, "name", "%s", tdmi->tdmi_network ?: "Unknown"); - - n = m = 0; - LIST_FOREACH(t, &tdmi->tdmi_transports, tht_mux_link) { - n++; - if(transport_is_available(t)) - m++; - } - ajax_table_cell(&ta, "nsvc", "%d / %d", m, n); - ajax_table_cell_checkbox(&ta); - } - - ajax_table_row_start(&ta, NULL); - - ajax_table_cell(&ta, NULL, - "All", tda->tda_identifier); - - ajax_table_bottom(&ta); - - htsbuf_qprintf(tq, "
    "); - - ajax_button(tq, "Select all", "mux_sel_all()"); - ajax_button(tq, "Select none", "mux_sel_none()"); - ajax_button(tq, "Delete selected...", - "mux_sel_do('dvbadapterdelmux/%s', '', '', true)", - tda->tda_identifier); - htsbuf_qprintf(tq, "
    \r\n"); - } - if(tda->tda_fe_info != NULL) { - htsbuf_qprintf(tq, "
    "); - - ajax_button(tq, "Add new mux...", - "new Ajax.Updater('servicepane', " - "'/ajax/dvbadapteraddmux/%s', " - "{method: 'get', evalScripts: true})\"", - tda->tda_identifier); - htsbuf_qprintf(tq, "
    \r\n"); - } - http_output_html(hc, hr); - return 0; -} - -/** - * - */ -static int -dvbsvccmp(th_transport_t *a, th_transport_t *b) -{ - if(a->tht_dvb_mux_instance == b->tht_dvb_mux_instance) - return a->tht_dvb_service_id - b->tht_dvb_service_id; - - return a->tht_dvb_mux_instance->tdmi_fe_params.frequency - - b->tht_dvb_mux_instance->tdmi_fe_params.frequency; -} - -/** - * Display detailes about a mux - */ -static int -ajax_dvbmuxeditor(http_connection_t *hc, http_reply_t *hr, - const char *remain, void *opaque) -{ - th_dvb_mux_instance_t *tdmi; - htsbuf_queue_t *tq = &hr->hr_q; - char buf[1000]; - th_transport_t *t; - struct th_transport_tree tree; - int n = 0; - - if(remain == NULL || (tdmi = dvb_mux_find_by_identifier(remain)) == NULL) - return HTTP_STATUS_NOT_FOUND; - - tdmi_displayname(tdmi, buf, sizeof(buf)); - - RB_INIT(&tree); - - LIST_FOREACH(t, &tdmi->tdmi_transports, tht_mux_link) { - if(transport_is_available(t)) { - RB_INSERT_SORTED(&tree, t, tht_tmp_link, dvbsvccmp); - n++; - } - } - - ajax_box_begin(tq, AJAX_BOX_SIDEBOX, NULL, NULL, buf); - ajax_transport_build_list(hc, tq, &tree, n); - ajax_box_end(tq, AJAX_BOX_SIDEBOX); - - http_output_html(hc, hr); - return 0; -} - -/** - * Display all transports on an adapter - */ -static int -ajax_dvbmuxall(http_connection_t *hc, http_reply_t *hr, - const char *remain, void *opaque) -{ - th_dvb_adapter_t *tda; - th_dvb_mux_instance_t *tdmi; - htsbuf_queue_t *tq = &hr->hr_q; - th_transport_t *t; - struct th_transport_tree tree; - int n = 0; - char buf[100]; - - if(remain == NULL || (tda = dvb_adapter_find_by_identifier(remain)) == NULL) - return HTTP_STATUS_NOT_FOUND; - - snprintf(buf, sizeof(buf), "All services on %s\n", tda->tda_displayname); - - RB_INIT(&tree); - - RB_FOREACH(tdmi, &tda->tda_muxes, tdmi_adapter_link) { - LIST_FOREACH(t, &tdmi->tdmi_transports, tht_mux_link) { - if(transport_is_available(t)) { - RB_INSERT_SORTED(&tree, t, tht_tmp_link, dvbsvccmp); - n++; - } - } - } - - ajax_box_begin(tq, AJAX_BOX_SIDEBOX, NULL, NULL, buf); - ajax_transport_build_list(hc, tq, &tree, n); - ajax_box_end(tq, AJAX_BOX_SIDEBOX); - - http_output_html(hc, hr); - return 0; -} - - -/** - * Delete muxes on an adapter - */ -static int -ajax_adapterdelmux(http_connection_t *hc, http_reply_t *hr, - const char *remain, void *opaque) -{ - th_dvb_adapter_t *tda; - th_dvb_mux_instance_t *tdmi; - htsbuf_queue_t *tq = &hr->hr_q; - http_arg_t *ra; - - if(remain == NULL || (tda = dvb_adapter_find_by_identifier(remain)) == NULL) - return HTTP_STATUS_NOT_FOUND; - - TAILQ_FOREACH(ra, &hc->hc_req_args, link) { - if(strcmp(ra->val, "selected")) - continue; - - if((tdmi = dvb_mux_find_by_identifier(ra->key)) == NULL) - continue; - - dvb_mux_destroy(tdmi); - } - - htsbuf_qprintf(tq, - "new Ajax.Updater('dvbadaptereditor', " - "'/ajax/dvbadaptereditor/%s', " - "{method: 'get', evalScripts: true});", - tda->tda_identifier); - - http_output(hc, hr, "text/javascript; charset=UTF8", NULL, 0); - return 0; -} - -/** - * Rename adapter - */ -static int -ajax_adapterrename(http_connection_t *hc, http_reply_t *hr, - const char *remain, void *opaque) -{ - th_dvb_adapter_t *tda; - - htsbuf_queue_t *tq = &hr->hr_q; - const char *s; - - if(remain == NULL || (tda = dvb_adapter_find_by_identifier(remain)) == NULL) - return HTTP_STATUS_NOT_FOUND; - - if((s = http_arg_get(&hc->hc_req_args, "newname")) == NULL) - return HTTP_STATUS_BAD_REQUEST; - - free(tda->tda_displayname); - tda->tda_displayname = strdup(s); - dvb_tda_save(tda); - - htsbuf_qprintf(tq, - "$('adaptername_%s').innerHTML='%s';", - tda->tda_identifier, tda->tda_displayname); - - htsbuf_qprintf(tq, - "new Ajax.Updater('summary_%s', " - "'/ajax/dvbadaptersummary/%s', {method: 'get'})", - tda->tda_identifier, tda->tda_identifier); - - http_output(hc, hr, "text/javascript; charset=UTF8", NULL, 0); - return 0; -} - - -/** - * Rename adapter - */ -static int -ajax_dvbnetworkinfo(http_connection_t *hc, http_reply_t *hr, - const char *remain, void *opaque) -{ - htsbuf_queue_t *tq = &hr->hr_q; - const char *s; - - if(remain == NULL) - return HTTP_STATUS_NOT_FOUND; - - if(dvb_mux_preconf_get(atoi(remain), NULL, &s) >= 0) - htsbuf_qprintf(tq, "%s", s); - - http_output_html(hc, hr); - return 0; -} - - - - -/** - * Rename adapter - */ -static int -ajax_dvbadapteraddnetwork(http_connection_t *hc, http_reply_t *hr, - const char *remain, void *opaque) -{ - htsbuf_queue_t *tq = &hr->hr_q; - const char *s; - th_dvb_adapter_t *tda; - - - if(remain == NULL || (tda = dvb_adapter_find_by_identifier(remain)) == NULL) - return HTTP_STATUS_NOT_FOUND; - - if((s = http_arg_get(&hc->hc_req_args, "network")) == NULL) - return HTTP_STATUS_BAD_REQUEST; - - - dvb_mux_preconf_add(tda, atoi(s)); - - htsbuf_qprintf(tq, - "$('servicepane').innerHTML='';\r\n"); - - htsbuf_qprintf(tq, - "new Ajax.Updater('dvbmuxlist_%s', " - "'/ajax/dvbadaptermuxlist/%s', " - "{method: 'get', evalScripts: true});\r\n", - tda->tda_identifier, tda->tda_identifier); - - - http_output(hc, hr, "text/javascript; charset=UTF8", NULL, 0); - return 0; -} - -/** - * Clone adapter - */ -static int -ajax_dvbadapterclone(http_connection_t *hc, http_reply_t *hr, - const char *remain, void *opaque) -{ - htsbuf_queue_t *tq = &hr->hr_q; - th_dvb_adapter_t *src, *dst; - const char *s; - - if(remain == NULL || (dst = dvb_adapter_find_by_identifier(remain)) == NULL) - return HTTP_STATUS_NOT_FOUND; - - if((s = http_arg_get(&hc->hc_req_args, "source")) == NULL) - return HTTP_STATUS_BAD_REQUEST; - - if((src = dvb_adapter_find_by_identifier(s)) == NULL) - return HTTP_STATUS_BAD_REQUEST; - - printf("Clone from %s to %s\n", src->tda_displayname, dst->tda_displayname); - - dvb_tda_clone(dst, src); - - htsbuf_qprintf(tq, "new Ajax.Updater('dvbadaptereditor', " - "'/ajax/dvbadaptereditor/%s', " - "{method: 'get', evalScripts: true});\r\n", - dst->tda_identifier); - - http_output(hc, hr, "text/javascript; charset=UTF8", NULL, 0); - return 0; -} - - -/** - * Delete adapter - */ -static int -ajax_dvbadapterdelete(http_connection_t *hc, http_reply_t *hr, - const char *remain, void *opaque) -{ - htsbuf_queue_t *tq = &hr->hr_q; - th_dvb_adapter_t *tda; - - if(remain == NULL || (tda = dvb_adapter_find_by_identifier(remain)) == NULL) - return HTTP_STATUS_NOT_FOUND; - - htsbuf_qprintf(tq, "var o = $('summary_%s'); o.parentNode.removeChild(o);\r\n", - tda->tda_identifier); - htsbuf_qprintf(tq, "$('dvbadaptereditor').innerHTML ='';\r\n"); - - dvb_tda_destroy(tda); - - http_output(hc, hr, "text/javascript; charset=UTF8", NULL, 0); - return 0; -} - - -/** - * - */ -void -ajax_config_dvb_init(void) -{ - http_path_add("/ajax/dvbadaptermuxlist" , NULL, ajax_adaptermuxlist, - AJAX_ACCESS_CONFIG); - http_path_add("/ajax/dvbadaptersummary" , NULL, ajax_adaptersummary, - AJAX_ACCESS_CONFIG); - http_path_add("/ajax/dvbadapterrename" , NULL, ajax_adapterrename, - AJAX_ACCESS_CONFIG); - http_path_add("/ajax/dvbadaptereditor", NULL, ajax_adaptereditor, - AJAX_ACCESS_CONFIG); - http_path_add("/ajax/dvbadapteraddmux", NULL, ajax_adapteraddmux, - AJAX_ACCESS_CONFIG); - http_path_add("/ajax/dvbadapterdelmux", NULL, ajax_adapterdelmux, - AJAX_ACCESS_CONFIG); - http_path_add("/ajax/dvbadaptercreatemux", NULL, ajax_adaptercreatemux, - AJAX_ACCESS_CONFIG); - http_path_add("/ajax/dvbmuxeditor", NULL, ajax_dvbmuxeditor, - AJAX_ACCESS_CONFIG); - http_path_add("/ajax/dvbmuxall", NULL, ajax_dvbmuxall, - AJAX_ACCESS_CONFIG); - http_path_add("/ajax/dvbnetworkinfo", NULL, ajax_dvbnetworkinfo, - AJAX_ACCESS_CONFIG); - http_path_add("/ajax/dvbadapteraddnetwork", NULL, ajax_dvbadapteraddnetwork, - AJAX_ACCESS_CONFIG); - http_path_add("/ajax/dvbadapterclone", NULL, ajax_dvbadapterclone, - AJAX_ACCESS_CONFIG); - http_path_add("/ajax/dvbadapterdelete", NULL, ajax_dvbadapterdelete, - AJAX_ACCESS_CONFIG); - -} diff --git a/ajaxui/ajaxui_config_transport.c b/ajaxui/ajaxui_config_transport.c deleted file mode 100644 index a6f357a3..00000000 --- a/ajaxui/ajaxui_config_transport.c +++ /dev/null @@ -1,338 +0,0 @@ -/* - * tvheadend, AJAX / HTML user interface - * Copyright (C) 2008 Andreas Öman - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#define _GNU_SOURCE - -#include -#include -#include -#include -#include -#include - -#include "tvhead.h" -#include "http.h" -#include "ajaxui.h" -#include "channels.h" -#include "psi.h" -#include "transports.h" -#include "serviceprobe.h" - - -/** - * - */ -int -ajax_transport_build_list(http_connection_t *hc, htsbuf_queue_t *tq, - struct th_transport_tree *tlist, int numtransports) -{ - th_transport_t *t; - ajax_table_t ta; - - htsbuf_qprintf(tq, "\r\n"); - - /* Top */ - - htsbuf_qprintf(tq, "
    "); - - ajax_table_top(&ta, hc, tq, - (const char *[]){"Last status", "Crypto", - "Type", "Source service", - "", "Target channel", "", NULL}, - (int[]){8,4,4,12,3,12,1}); - - RB_FOREACH(t, tlist, tht_tmp_link) { - ajax_table_row_start(&ta, t->tht_identifier); - - ajax_table_cell(&ta, "status", - transport_status_to_text(t->tht_last_status)); - ajax_table_cell(&ta, NULL, "%s", t->tht_scrambled ? "Yes" : "No"); - ajax_table_cell(&ta, NULL, "%s", transport_servicetype_txt(t)); - ajax_table_cell(&ta, NULL, "%s", t->tht_svcname ?: ""); - - ajax_table_cell(&ta, NULL, - "" - "", - t->tht_identifier, t->tht_identifier, - t->tht_ch ? "" : "un"); - - if(t->tht_ch == NULL) { - /* Unmapped */ - ajax_table_cell(&ta, "chname", - "" - "%s", - t->tht_identifier, t->tht_identifier, - t->tht_chname, t->tht_chname); - } else { - ajax_table_cell(&ta, "chname", "%s", t->tht_ch->ch_name); - } - - ajax_table_cell_checkbox(&ta); - } - - ajax_table_bottom(&ta); - - htsbuf_qprintf(tq, "
    \r\n"); - - htsbuf_qprintf(tq, "
    "); - - ajax_button(tq, "Select all", "select_all()"); - ajax_button(tq, "Select none", "select_none()"); - - // htsbuf_qprintf(tq, "
    \r\n"); - //htsbuf_qprintf(tq, "
    "); - - ajax_button(tq, "Map selected", "selected_do('map');"); - ajax_button(tq, "Unmap selected", "selected_do('unmap');"); - ajax_button(tq, "Test and map selected", "selected_do('probe');"); - htsbuf_qprintf(tq, "
    "); - - htsbuf_qprintf(tq, "
    "); - return 0; -} - -/** - * Rename of unmapped channel - */ -static int -ajax_transport_rename_channel(http_connection_t *hc, http_reply_t *hr, - const char *remain, void *opaque) -{ - th_transport_t *t; - const char *newname; - htsbuf_queue_t *tq = &hr->hr_q; - - if(remain == NULL || (t = transport_find_by_identifier(remain)) == NULL) - return HTTP_STATUS_NOT_FOUND; - - if((newname = http_arg_get(&hc->hc_req_args, "newname")) == NULL) - return HTTP_STATUS_BAD_REQUEST; - - free((void *)t->tht_chname); - t->tht_chname = strdup(newname); - - ajax_a_jsfuncf(tq, newname, - "tentative_chname('chname_%s', " - "'/ajax/transport_rename_channel/%s', '%s')", - t->tht_identifier, t->tht_identifier, newname); - - http_output_html(hc, hr); - t->tht_config_change(t); - return 0; -} - - -/** - * - */ -void -ajax_transport_build_mapper_state(char *buf, size_t siz, th_transport_t *t, - int mapped) -{ - if(mapped) { - snprintf(buf, siz, - "$('chname_%s').innerHTML='%s';\n\r" - "$('map_%s').src='/gfx/mapped.png';\n\r", - t->tht_identifier, t->tht_ch->ch_name, - t->tht_identifier); - } else { - snprintf(buf, siz, - "$('chname_%s').innerHTML='" - "%s" - "';\n\r" - "$('map_%s').src='/gfx/unmapped.png';\n\r", - t->tht_identifier, t->tht_identifier, t->tht_identifier, - t->tht_chname, t->tht_chname, t->tht_identifier); - } -} - - -/** - * - */ -static void -ajax_map_unmap_channel(th_transport_t *t, htsbuf_queue_t *tq, int map) -{ - char buf[1000]; - - if(map) - transport_map_channel(t, NULL); - else - transport_unmap_channel(t); - - ajax_transport_build_mapper_state(buf, sizeof(buf), t, map); - htsbuf_qprintf(tq, "%s", buf); -} - - -/** - * - */ -static int -ajax_transport_op(http_connection_t *hc, http_reply_t *hr, - const char *remain, void *opaque) -{ - th_transport_t *t; - htsbuf_queue_t *tq = &hr->hr_q; - const char *op = remain; - http_arg_t *ra; - - if(op == NULL) - return HTTP_STATUS_NOT_FOUND; - - TAILQ_FOREACH(ra, &hc->hc_req_args, link) { - if(strcmp(ra->val, "selected")) - continue; - - if((t = transport_find_by_identifier(ra->key)) == NULL) - continue; - - if(!strcmp(op, "toggle")) { - ajax_map_unmap_channel(t, tq, t->tht_ch ? 0 : 1); - } else if(!strcmp(op, "map") && t->tht_ch == NULL) { - ajax_map_unmap_channel(t, tq, 1); - } else if(!strcmp(op, "unmap") && t->tht_ch != NULL) { - ajax_map_unmap_channel(t, tq, 0); - } else if(!strcmp(op, "probe")) { - serviceprobe_add(t); - continue; - } - t->tht_config_change(t); - } - - http_output(hc, hr, "text/javascript; charset=UTF8", NULL, 0); - - return 0; -} - - -/** - * - */ -static int -ajax_transport_chdisable(http_connection_t *hc, http_reply_t *hr, - const char *remain, void *opaque) -{ - th_transport_t *t; - const char *s; - - if(remain == NULL || (t = transport_find_by_identifier(remain)) == NULL) - return HTTP_STATUS_NOT_FOUND; - - if((s = http_arg_get(&hc->hc_req_args, "enabled")) == NULL) - return HTTP_STATUS_BAD_REQUEST; - - t->tht_disabled = !strcasecmp(s, "false"); - http_output(hc, hr, "text/javascript; charset=UTF8", NULL, 0); - t->tht_config_change(t); - return 0; -} - - -/** - * - */ -void -ajax_config_transport_init(void) -{ - http_path_add("/ajax/transport_rename_channel", NULL, - ajax_transport_rename_channel, - AJAX_ACCESS_CONFIG); - - http_path_add("/ajax/transport_op", NULL, - ajax_transport_op, - AJAX_ACCESS_CONFIG); - - http_path_add("/ajax/transport_chdisable", NULL, - ajax_transport_chdisable, - AJAX_ACCESS_CONFIG); - -} diff --git a/ajaxui/ajaxui_config_xmltv.c b/ajaxui/ajaxui_config_xmltv.c deleted file mode 100644 index d5f96e14..00000000 --- a/ajaxui/ajaxui_config_xmltv.c +++ /dev/null @@ -1,334 +0,0 @@ -/* - * tvheadend, AJAX / HTML user interface - * Copyright (C) 2008 Andreas Öman - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#define _GNU_SOURCE - -#include -#include -#include -#include -#include -#include - -#include "tvhead.h" -#include "http.h" -#include "ajaxui.h" -#include "channels.h" -#include "epg_xmltv.h" -#include "psi.h" -#include "transports.h" - -#include "ajaxui_mailbox.h" - - - -/** - * XMLTV configuration - */ -int -ajax_config_xmltv_tab(http_connection_t *hc, http_reply_t *hr) -{ - htsbuf_queue_t *tq = &hr->hr_q; - xmltv_grabber_t *xg; - int ngrabbers = 0; - ajax_table_t ta; - - htsbuf_qprintf(tq, "
    "); - - switch(xmltv_globalstatus) { - default: - htsbuf_qprintf(tq, "

    " - "XMLTV subsystem is not yet fully initialized, please retry " - "in a few seconds

    "); - http_output_html(hc, hr); - return 0; - - case XMLTVSTATUS_FIND_GRABBERS_NOT_FOUND: - htsbuf_qprintf(tq, "

    " - "XMLTV subsystem can not initialize

    " - "

    " - "Make sure that the 'tv_find_grabbers' executable is in " - "the system path

    "); - http_output_html(hc, hr); - return 0; - - case XMLTVSTATUS_RUNNING: - break; - } - - htsbuf_qprintf(tq, "
    "); - - ajax_box_begin(tq, AJAX_BOX_SIDEBOX, NULL, NULL, "XMLTV grabbers"); - - LIST_FOREACH(xg, &xmltv_grabbers, xg_link) - ngrabbers++; - - ajax_table_top(&ta, hc, tq, - (const char *[]){"Grabber", "Status", NULL}, - (int[]){4,2}); - - LIST_FOREACH(xg, &xmltv_grabbers, xg_link) { - - ajax_table_row_start(&ta, xg->xg_identifier); - ajax_table_cell(&ta, NULL, - "%s", xg->xg_identifier, xg->xg_title); - - ajax_table_cell(&ta, "status", xmltv_grabber_status(xg)); - } - ajax_table_bottom(&ta); - - ajax_box_end(tq, AJAX_BOX_SIDEBOX); - - htsbuf_qprintf(tq, "
    " - "
    " - "
    "); - - htsbuf_qprintf(tq, ""); - http_output_html(hc, hr); - return 0; -} - -/** - * Generate displaylisting - */ -static void -xmltv_grabber_chlist(htsbuf_queue_t *tq, xmltv_grabber_t *xg) -{ - xmltv_channel_t *xc; - channel_group_t *tcg; - channel_t *ch; - - htsbuf_qprintf(tq, - "
    "); - - TAILQ_FOREACH(xc, &xg->xg_channels, xc_link) { - - htsbuf_qprintf(tq, - "
    "); - - htsbuf_qprintf(tq, "
    "); - if(xc->xc_icon_url != NULL) { - htsbuf_qprintf(tq, - "", - xc->xc_icon_url); - } else { - htsbuf_qprintf(tq, - "
    " - "No icon
    "); - } - htsbuf_qprintf(tq, "
    "); /* iconbackdrop */ - - - htsbuf_qprintf(tq, - "
    Name:
    " - "
    %s (%s)
    ", xc->xc_displayname, xc->xc_name); - - htsbuf_qprintf(tq, - "
    Auto mapper:
    " - "
    %s
    ", xc->xc_bestmatch ?: "(no channel)"); - - htsbuf_qprintf(tq, - "
    Channel:
    " - ""); - htsbuf_qprintf(tq, "

    \r\n"); - } - htsbuf_qprintf(tq, "
    "); -} - - -/** - * Display detailes about a grabber - */ -static int -ajax_xmltvgrabber(http_connection_t *hc, http_reply_t *hr, - const char *remain, void *opaque) -{ - xmltv_grabber_t *xg; - htsbuf_queue_t *tq = &hr->hr_q; - - - if(remain == NULL || (xg = xmltv_grabber_find(remain)) == NULL) - return HTTP_STATUS_NOT_FOUND; - - ajax_box_begin(tq, AJAX_BOX_SIDEBOX, NULL, NULL, xg->xg_title); - - htsbuf_qprintf(tq,"
    ", xg->xg_identifier); - - if(xg->xg_enabled == 0) { - htsbuf_qprintf(tq, - "

    This grabber is currently not enabled, click " - "here " - "to enable it

    "); - } else if(xg->xg_status == XMLTV_GRAB_OK) { - xmltv_grabber_chlist(tq, xg); - } else { - htsbuf_qprintf(tq, "

    %s

    ", xmltv_grabber_status_long(xg)); - } - - htsbuf_qprintf(tq,"
    "); - - ajax_box_end(tq, AJAX_BOX_SIDEBOX); - http_output_html(hc, hr); - return 0; -} - - - -/** - * Enable / Disable a grabber - */ -static int -ajax_xmltvgrabbermode(http_connection_t *hc, http_reply_t *hr, - const char *remain, void *opaque) -{ - xmltv_grabber_t *xg; - htsbuf_queue_t *tq = &hr->hr_q; - - if(remain == NULL || (xg = xmltv_grabber_find(remain)) == NULL) - return HTTP_STATUS_NOT_FOUND; - - xmltv_grabber_enable(xg); - - htsbuf_qprintf(tq,"$('details_%s').innerHTML='Please wait...';", - xg->xg_identifier); - - http_output(hc, hr, "text/javascript; charset=UTF8", NULL, 0); - return 0; -} - - - -/** - * Enable / Disable a grabber - */ -static int -ajax_xmltvgrabberlist(http_connection_t *hc, http_reply_t *hr, - const char *remain, void *opaque) -{ - xmltv_grabber_t *xg; - htsbuf_queue_t *tq = &hr->hr_q; - - if(remain == NULL || (xg = xmltv_grabber_find(remain)) == NULL) - return HTTP_STATUS_NOT_FOUND; - - xmltv_grabber_chlist(tq, xg); - - http_output_html(hc, hr); - return 0; -} - - -/** - * Change mapping of a channel for a grabber - */ -static int -ajax_xmltvgrabberchmap(http_connection_t *hc, http_reply_t *hr, - const char *remain, void *opaque) -{ - xmltv_grabber_t *xg; - xmltv_channel_t *xc; - const char *xmltvname; - const char *chname; - channel_t *ch; - // htsbuf_queue_t *tq = &hr->hr_tq; - - if(remain == NULL || (xg = xmltv_grabber_find(remain)) == NULL) - return HTTP_STATUS_NOT_FOUND; - - if((xmltvname = http_arg_get(&hc->hc_req_args, "xmltvch")) == NULL) - return HTTP_STATUS_BAD_REQUEST; - - if((chname = http_arg_get(&hc->hc_req_args, "channel")) == NULL) - return HTTP_STATUS_BAD_REQUEST; - - TAILQ_FOREACH(xc, &xg->xg_channels, xc_link) - if(!strcmp(xc->xc_name, xmltvname)) - break; - - if(xc == NULL) - return HTTP_STATUS_BAD_REQUEST; - - pthread_mutex_lock(&xg->xg_mutex); - - free(xc->xc_channel); - xc->xc_channel = NULL; - xc->xc_disabled = 0; - - if(!strcmp(chname, "none")) { - xc->xc_disabled = 1; - } else if(!strcmp(chname, "auto")) { - } else if((ch = channel_by_tag(atoi(chname))) != NULL) { - xc->xc_disabled = 0; - xc->xc_channel = strdup(ch->ch_name); - } - pthread_mutex_unlock(&xg->xg_mutex); - - xmltv_config_save(); - - http_output(hc, hr, "text/javascript; charset=UTF8", NULL, 0); - return 0; -} - - - -/** - * - */ -void -ajax_config_xmltv_init(void) -{ - http_path_add("/ajax/xmltvgrabber" , NULL, ajax_xmltvgrabber, - AJAX_ACCESS_CONFIG); - http_path_add("/ajax/xmltvgrabbermode" , NULL, ajax_xmltvgrabbermode, - AJAX_ACCESS_CONFIG); - http_path_add("/ajax/xmltvgrabberlist" , NULL, ajax_xmltvgrabberlist, - AJAX_ACCESS_CONFIG); - http_path_add("/ajax/xmltvgrabberchmap" , NULL, ajax_xmltvgrabberchmap, - AJAX_ACCESS_CONFIG); - -} diff --git a/ajaxui/ajaxui_mailbox.c b/ajaxui/ajaxui_mailbox.c deleted file mode 100644 index f43203c2..00000000 --- a/ajaxui/ajaxui_mailbox.c +++ /dev/null @@ -1,502 +0,0 @@ -/* - * tvheadend, AJAX / HTML Mailboxes - * Copyright (C) 2008 Andreas Öman - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include -#include -#include -#include -#include -#include - -#include - -#include "tvhead.h" -#include "dispatch.h" -#include "http.h" -#include "ajaxui.h" -#include "transports.h" -#include "epg_xmltv.h" -#include "dvb_support.h" -#include "ajaxui_mailbox.h" -#include "cwc.h" - -#define MAILBOX_UNUSED_TIMEOUT 15 -#define MAILBOX_EMPTY_REPLY_TIMEOUT 10 - - -//#define mbdebug(fmt...) printf(fmt); -#define mbdebug(fmt...) - - -static LIST_HEAD(, ajaxui_mailbox) mailboxes; - -int mailbox_tally; - -TAILQ_HEAD(ajaxui_letter_queue, ajaxui_letter); - -typedef struct ajaxui_letter { - TAILQ_ENTRY(ajaxui_letter) al_link; - char *al_payload_a; - char *al_payload_b; -} ajaxui_letter_t; - - -typedef struct ajaxui_mailbox { - LIST_ENTRY(ajaxui_mailbox) amb_link; - - char *amb_boxid; /* an md5hash */ - - dtimer_t amb_timer; - - http_reply_t *amb_hr; /* Pending request */ - - struct ajaxui_letter_queue amb_letters; - -} ajaxui_mailbox_t; - - -/** - * - */ -static void -al_destroy(ajaxui_mailbox_t *amb, ajaxui_letter_t *al) -{ - TAILQ_REMOVE(&amb->amb_letters, al, al_link); - free(al->al_payload_a); - free(al->al_payload_b); - free(al); -} - - -/** - * - */ -static void -amb_destroy(ajaxui_mailbox_t *amb) -{ - ajaxui_letter_t *al; - - mbdebug("mailbox[%s]: destroyed\n", amb->amb_boxid); - - while((al = TAILQ_FIRST(&amb->amb_letters)) != NULL) - al_destroy(amb, al); - - LIST_REMOVE(amb, amb_link); - - dtimer_disarm(&amb->amb_timer); - - free(amb->amb_boxid); - free(amb); -} - - - -/** - * - */ -static void -ajax_mailbox_unused(void *opaque, int64_t now) -{ - ajaxui_mailbox_t *amb = opaque; - assert(amb->amb_hr == NULL); - amb_destroy(amb); -} - -/** - * - */ -static void -ajax_mailbox_connection_lost(http_reply_t *hr, void *opaque) -{ - ajaxui_mailbox_t *amb = opaque; - assert(hr == amb->amb_hr); - amb_destroy(amb); -} - - - -/** - * - */ -static ajaxui_mailbox_t * -ajax_mailbox_create(const char *id) -{ - ajaxui_mailbox_t *amb = calloc(1, sizeof(ajaxui_mailbox_t)); - - amb->amb_boxid = strdup(id); - - mailbox_tally++; - - LIST_INSERT_HEAD(&mailboxes, amb, amb_link); - - TAILQ_INIT(&amb->amb_letters); - - dtimer_arm(&amb->amb_timer, ajax_mailbox_unused, amb, - MAILBOX_UNUSED_TIMEOUT); - return amb; -} - -/** - * - */ -void -ajax_mailbox_start(htsbuf_queue_t *hq) -{ - struct timeval tv; - uint8_t sum[16]; - char id[33]; - int i; - struct AVMD5 *ctx; - - ctx = alloca(av_md5_size); - - gettimeofday(&tv, NULL); - - av_md5_init(ctx); - av_md5_update(ctx, (void *)&tv, sizeof(tv)); - av_md5_update(ctx, (void *)&mailbox_tally, sizeof(uint32_t)); - av_md5_final(ctx, sum); - - for(i = 0; i < 16; i++) { - id[i * 2 + 0] = "0123456789abcdef"[sum[i] >> 4]; - id[i * 2 + 1] = "0123456789abcdef"[sum[i] & 15]; - } - id[32] = 0; - - mbdebug("Generated mailbox %s\n", id); - - ajax_mailbox_create(id); - ajax_js(hq, "mailboxquery('%s')", id); -} - - -/** - * - */ -static void -ajax_mailbox_reply(ajaxui_mailbox_t *amb, http_reply_t *hr) -{ - ajaxui_letter_t *al; - - /* Modify the hidden element (as described in ajax_mailbox_start()), - if this div no longer exist, the rest of the javascript will bail - out and we will not be reloaded */ - - mbdebug("mailbox[%s]: sending reply\n", amb->amb_boxid); - - while((al = TAILQ_FIRST(&amb->amb_letters)) != NULL) { - htsbuf_qprintf(&hr->hr_q, "try {\r\n"); - htsbuf_qprintf(&hr->hr_q, "%s%s", - al->al_payload_a, al->al_payload_b ?: ""); - mbdebug("\t%s%s", al->al_payload_a, al->al_payload_b ?: ""); - - htsbuf_qprintf(&hr->hr_q, "}\r\n" - "catch(err) {}\r\n"); - al_destroy(amb, al); - } - - htsbuf_qprintf(&hr->hr_q, "mailboxquery('%s');\r\n", amb->amb_boxid); - - http_output(hr->hr_connection, hr, "text/javascript", NULL, 0); - amb->amb_hr = NULL; - - /* Arm a timer in case the browser won't call back */ - dtimer_arm(&amb->amb_timer, ajax_mailbox_unused, amb, - MAILBOX_UNUSED_TIMEOUT); -} - -/** - * - */ -static void -ajax_mailbox_empty_reply(void *opaque, int64_t now) -{ - ajaxui_mailbox_t *amb = opaque; - http_reply_t *hr = amb->amb_hr; - - ajax_mailbox_reply(amb, hr); - http_continue(hr->hr_connection); -} - - -/** - * Poll callback - * - * Prepare the mailbox for reply - */ -static int -ajax_mailbox_poll(http_connection_t *hc, http_reply_t *hr, - const char *remain, void *opaque) -{ - ajaxui_mailbox_t *amb; - - if(remain == NULL) - return HTTP_STATUS_NOT_FOUND; - - mbdebug("mailbox[%s]: Incomming request ... ", remain); - - LIST_FOREACH(amb, &mailboxes, amb_link) - if(!strcmp(amb->amb_boxid, remain)) - break; - - if(amb == NULL) { - amb = ajax_mailbox_create(remain); - mbdebug("creating mailbox ... "); - } - - if(amb->amb_hr != NULL) { - mbdebug("mailbox already processing\n"); - return 409; - } - if(TAILQ_FIRST(&amb->amb_letters) != NULL) { - /* Pending letters, direct reply */ - mbdebug("direct reply\n"); - ajax_mailbox_reply(amb, hr); - return 0; - } - - mbdebug("nothing in queue, waiting\n"); - - amb->amb_hr = hr; - - hr->hr_opaque = amb; - hr->hr_destroy = ajax_mailbox_connection_lost; - - dtimer_arm(&amb->amb_timer, ajax_mailbox_empty_reply, amb, - MAILBOX_EMPTY_REPLY_TIMEOUT); - return 0; -} - - -/** - * - */ -void -ajax_mailbox_init(void) -{ - http_path_add("/ajax/mailbox", NULL, ajax_mailbox_poll, - ACCESS_WEB_INTERFACE); -} - - -/** - * Delayed delivery of mailbox replies - */ -static void -ajax_mailbox_deliver(void *opaque, int64_t now) -{ - ajaxui_mailbox_t *amb = opaque; - http_connection_t *hc; - - hc = amb->amb_hr->hr_connection; - ajax_mailbox_reply(amb, amb->amb_hr); - http_continue(hc); -} - -/** - * - */ -static void -ajax_mailbox_add_to_subscription(const char *subscription, - const char *content_a, const char *content_b) -{ - ajaxui_mailbox_t *amb; - ajaxui_letter_t *al; - - LIST_FOREACH(amb, &mailboxes, amb_link) { - - /* Avoid inserting the same message twice */ - - TAILQ_FOREACH(al, &amb->amb_letters, al_link) { - if(!strcmp(al->al_payload_a, content_a)) - break; - } - - if(al == NULL) { - - al = malloc(sizeof(ajaxui_letter_t)); - al->al_payload_a = strdup(content_a); - } else { - /* Already exist, just move to tail */ - - TAILQ_REMOVE(&amb->amb_letters, al, al_link); - free(al->al_payload_b); - } - - al->al_payload_b = content_b ? strdup(content_b) : NULL; - - TAILQ_INSERT_TAIL(&amb->amb_letters, al, al_link); - - if(amb->amb_hr != NULL) - dtimer_arm_hires(&amb->amb_timer, ajax_mailbox_deliver, amb, - getclock_hires() + 100000); - } -} - - - -/** - * - */ -static void -ajax_mailbox_update_div(const char *subscription, const char *prefix, - const char *postfix, const char *content) -{ - char buf_a[500]; - char buf_b[500]; - - content = ajaxui_escape_apostrophe(content); - - snprintf(buf_a, sizeof(buf_a), "$('%s_%s').innerHTML=", prefix, postfix); - snprintf(buf_b, sizeof(buf_b), "'%s';\n\r", content); - - ajax_mailbox_add_to_subscription(subscription, buf_a, buf_b); -} - - - -static void -ajax_mailbox_reload_div(const char *subscription, const char *prefix, - const char *postfix, const char *url) -{ - char buf[1000]; - - snprintf(buf, sizeof(buf), "new Ajax.Updater('%s_%s', '%s', " - "{method: 'get', evalScripts: true});\r\n", - prefix, postfix, url); - - ajax_mailbox_add_to_subscription(subscription, buf, NULL); -} - - - -void -ajax_mailbox_tdmi_state_change(th_dvb_mux_instance_t *tdmi) -{ - ajax_mailbox_update_div(tdmi->tdmi_adapter->tda_identifier, - "state", tdmi->tdmi_identifier, - dvb_mux_state(tdmi)); -} - -void -ajax_mailbox_tdmi_qual_change(th_dvb_mux_instance_t *tdmi) -{ - char buf[10]; - snprintf(buf, sizeof(buf), "%d%%", - dvb_quality_to_percent(tdmi->tdmi_quality)); - ajax_mailbox_update_div(tdmi->tdmi_adapter->tda_identifier, - "qual", tdmi->tdmi_identifier, - buf); -} - - -void -ajax_mailbox_tdmi_name_change(th_dvb_mux_instance_t *tdmi) -{ - ajax_mailbox_update_div(tdmi->tdmi_adapter->tda_identifier, - "name", tdmi->tdmi_identifier, - tdmi->tdmi_network ?: ""); -} - - -void -ajax_mailbox_tdmi_status_change(th_dvb_mux_instance_t *tdmi) -{ - ajax_mailbox_update_div(tdmi->tdmi_adapter->tda_identifier, - "status", tdmi->tdmi_identifier, - tdmi->tdmi_last_status); -} - -void -ajax_mailbox_tdmi_services_change(th_dvb_mux_instance_t *tdmi) -{ - th_transport_t *t; - char buf[20]; - int n, m; - - n = m = 0; - LIST_FOREACH(t, &tdmi->tdmi_transports, tht_mux_link) { - n++; - if(transport_is_available(t)) - m++; - } - snprintf(buf, sizeof(buf), "%d / %d", m, n); - - ajax_mailbox_update_div(tdmi->tdmi_adapter->tda_identifier, - "nsvc", tdmi->tdmi_identifier, - buf); -} - - -void -ajax_mailbox_tda_change(th_dvb_adapter_t *tda) -{ - char buf[500]; - - snprintf(buf, sizeof(buf), "/ajax/dvbadaptermuxlist/%s", - tda->tda_identifier); - - ajax_mailbox_reload_div(tda->tda_identifier, - "dvbmuxlist", tda->tda_identifier, - buf); -} - - -void -ajax_mailbox_xmltv_grabber_status_change(xmltv_grabber_t *xg) -{ - char buf[500]; - - ajax_mailbox_update_div("xmltvgrabbers", - "status", xg->xg_identifier, - xmltv_grabber_status(xg)); - - - if(xg->xg_status == XMLTV_GRAB_OK) { - snprintf(buf, sizeof(buf), "/ajax/xmltvgrabberlist/%s", xg->xg_identifier); - ajax_mailbox_reload_div("xmltvgrabbers", - "details", xg->xg_identifier, - buf); - } else { - ajax_mailbox_update_div(xg->xg_identifier, - "details", xg->xg_identifier, - xmltv_grabber_status_long(xg)); - } -} - - - -void -ajax_mailbox_transport_status_change(struct th_transport *t) -{ - ajax_mailbox_update_div("xmltvgrabbers", - "status", t->tht_identifier, - transport_status_to_text(t->tht_last_status)); -} - - - - -void -ajax_mailbox_cwc_status_change(struct cwc *cwc) -{ - char id[20]; - snprintf(id, sizeof(id), "cwc_%d", cwc->cwc_id); - - ajax_mailbox_update_div("cwc", "status", id, cwc_status_to_text(cwc)); -} diff --git a/ajaxui/ajaxui_mailbox.h b/ajaxui/ajaxui_mailbox.h deleted file mode 100644 index 5bf3a992..00000000 --- a/ajaxui/ajaxui_mailbox.h +++ /dev/null @@ -1,48 +0,0 @@ -/* - * tvheadend, AJAX user interface - * Copyright (C) 2007 Andreas Öman - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef AJAXUI_MAILBOX_H_ -#define AJAXUI_MAILBOX_H_ - -#include - -void ajax_mailbox_tdmi_state_change(th_dvb_mux_instance_t *tdmi); - -void ajax_mailbox_tdmi_qual_change(th_dvb_mux_instance_t *tdmi); - -void ajax_mailbox_tdmi_name_change(th_dvb_mux_instance_t *tdmi); - -void ajax_mailbox_tdmi_status_change(th_dvb_mux_instance_t *tdmi); - -void ajax_mailbox_tdmi_services_change(th_dvb_mux_instance_t *tdmi); - -void ajax_mailbox_tda_change(th_dvb_adapter_t *tda); - -void ajax_mailbox_start(htsbuf_queue_t *hq); - -struct xmltv_grabber; - -void ajax_mailbox_xmltv_grabber_status_change(struct xmltv_grabber *xg); - -struct th_transport; -void ajax_mailbox_transport_status_change(struct th_transport *t); - -struct cwc; -void ajax_mailbox_cwc_status_change(struct cwc *cwc); - -#endif /* AJAXUI_MAILBOX_H_ */ diff --git a/ajaxui/images/mapped.png b/ajaxui/images/mapped.png deleted file mode 100644 index a4494940..00000000 Binary files a/ajaxui/images/mapped.png and /dev/null differ diff --git a/ajaxui/images/sbbody_l.gif b/ajaxui/images/sbbody_l.gif deleted file mode 100644 index a7adf2d3..00000000 Binary files a/ajaxui/images/sbbody_l.gif and /dev/null differ diff --git a/ajaxui/images/sbbody_r.gif b/ajaxui/images/sbbody_r.gif deleted file mode 100644 index 51c4b9fe..00000000 Binary files a/ajaxui/images/sbbody_r.gif and /dev/null differ diff --git a/ajaxui/images/sbhead_l.gif b/ajaxui/images/sbhead_l.gif deleted file mode 100644 index 1f4ab9b8..00000000 Binary files a/ajaxui/images/sbhead_l.gif and /dev/null differ diff --git a/ajaxui/images/sbhead_r.gif b/ajaxui/images/sbhead_r.gif deleted file mode 100644 index 2401d2a9..00000000 Binary files a/ajaxui/images/sbhead_r.gif and /dev/null differ diff --git a/ajaxui/images/unmapped.png b/ajaxui/images/unmapped.png deleted file mode 100644 index 0f2f7388..00000000 Binary files a/ajaxui/images/unmapped.png and /dev/null differ diff --git a/ajaxui/prototype/prototype.js b/ajaxui/prototype/prototype.js deleted file mode 100644 index 33ec9d9e..00000000 --- a/ajaxui/prototype/prototype.js +++ /dev/null @@ -1,4236 +0,0 @@ -/* Prototype JavaScript framework, version 1.6.0.2 - * (c) 2005-2007 Sam Stephenson - * - * Prototype is freely distributable under the terms of an MIT-style license. - * For details, see the Prototype web site: http://www.prototypejs.org/ - * - *--------------------------------------------------------------------------*/ - -var Prototype = { - Version: '1.6.0.2', - - Browser: { - IE: !!(window.attachEvent && !window.opera), - Opera: !!window.opera, - WebKit: navigator.userAgent.indexOf('AppleWebKit/') > -1, - Gecko: navigator.userAgent.indexOf('Gecko') > -1 && navigator.userAgent.indexOf('KHTML') == -1, - MobileSafari: !!navigator.userAgent.match(/Apple.*Mobile.*Safari/) - }, - - BrowserFeatures: { - XPath: !!document.evaluate, - ElementExtensions: !!window.HTMLElement, - SpecificElementExtensions: - document.createElement('div').__proto__ && - document.createElement('div').__proto__ !== - document.createElement('form').__proto__ - }, - - ScriptFragment: ']*>([\\S\\s]*?)<\/script>', - JSONFilter: /^\/\*-secure-([\s\S]*)\*\/\s*$/, - - emptyFunction: function() { }, - K: function(x) { return x } -}; - -if (Prototype.Browser.MobileSafari) - Prototype.BrowserFeatures.SpecificElementExtensions = false; - - -/* Based on Alex Arnell's inheritance implementation. */ -var Class = { - create: function() { - var parent = null, properties = $A(arguments); - if (Object.isFunction(properties[0])) - parent = properties.shift(); - - function klass() { - this.initialize.apply(this, arguments); - } - - Object.extend(klass, Class.Methods); - klass.superclass = parent; - klass.subclasses = []; - - if (parent) { - var subclass = function() { }; - subclass.prototype = parent.prototype; - klass.prototype = new subclass; - parent.subclasses.push(klass); - } - - for (var i = 0; i < properties.length; i++) - klass.addMethods(properties[i]); - - if (!klass.prototype.initialize) - klass.prototype.initialize = Prototype.emptyFunction; - - klass.prototype.constructor = klass; - - return klass; - } -}; - -Class.Methods = { - addMethods: function(source) { - var ancestor = this.superclass && this.superclass.prototype; - var properties = Object.keys(source); - - if (!Object.keys({ toString: true }).length) - properties.push("toString", "valueOf"); - - for (var i = 0, length = properties.length; i < length; i++) { - var property = properties[i], value = source[property]; - if (ancestor && Object.isFunction(value) && - value.argumentNames().first() == "$super") { - var method = value, value = Object.extend((function(m) { - return function() { return ancestor[m].apply(this, arguments) }; - })(property).wrap(method), { - valueOf: function() { return method }, - toString: function() { return method.toString() } - }); - } - this.prototype[property] = value; - } - - return this; - } -}; - -var Abstract = { }; - -Object.extend = function(destination, source) { - for (var property in source) - destination[property] = source[property]; - return destination; -}; - -Object.extend(Object, { - inspect: function(object) { - try { - if (Object.isUndefined(object)) return 'undefined'; - if (object === null) return 'null'; - return object.inspect ? object.inspect() : String(object); - } catch (e) { - if (e instanceof RangeError) return '...'; - throw e; - } - }, - - toJSON: function(object) { - var type = typeof object; - switch (type) { - case 'undefined': - case 'function': - case 'unknown': return; - case 'boolean': return object.toString(); - } - - if (object === null) return 'null'; - if (object.toJSON) return object.toJSON(); - if (Object.isElement(object)) return; - - var results = []; - for (var property in object) { - var value = Object.toJSON(object[property]); - if (!Object.isUndefined(value)) - results.push(property.toJSON() + ': ' + value); - } - - return '{' + results.join(', ') + '}'; - }, - - toQueryString: function(object) { - return $H(object).toQueryString(); - }, - - toHTML: function(object) { - return object && object.toHTML ? object.toHTML() : String.interpret(object); - }, - - keys: function(object) { - var keys = []; - for (var property in object) - keys.push(property); - return keys; - }, - - values: function(object) { - var values = []; - for (var property in object) - values.push(object[property]); - return values; - }, - - clone: function(object) { - return Object.extend({ }, object); - }, - - isElement: function(object) { - return object && object.nodeType == 1; - }, - - isArray: function(object) { - return object != null && typeof object == "object" && - 'splice' in object && 'join' in object; - }, - - isHash: function(object) { - return object instanceof Hash; - }, - - isFunction: function(object) { - return typeof object == "function"; - }, - - isString: function(object) { - return typeof object == "string"; - }, - - isNumber: function(object) { - return typeof object == "number"; - }, - - isUndefined: function(object) { - return typeof object == "undefined"; - } -}); - -Object.extend(Function.prototype, { - argumentNames: function() { - var names = this.toString().match(/^[\s\(]*function[^(]*\((.*?)\)/)[1].split(",").invoke("strip"); - return names.length == 1 && !names[0] ? [] : names; - }, - - bind: function() { - if (arguments.length < 2 && Object.isUndefined(arguments[0])) return this; - var __method = this, args = $A(arguments), object = args.shift(); - return function() { - return __method.apply(object, args.concat($A(arguments))); - } - }, - - bindAsEventListener: function() { - var __method = this, args = $A(arguments), object = args.shift(); - return function(event) { - return __method.apply(object, [event || window.event].concat(args)); - } - }, - - curry: function() { - if (!arguments.length) return this; - var __method = this, args = $A(arguments); - return function() { - return __method.apply(this, args.concat($A(arguments))); - } - }, - - delay: function() { - var __method = this, args = $A(arguments), timeout = args.shift() * 1000; - return window.setTimeout(function() { - return __method.apply(__method, args); - }, timeout); - }, - - wrap: function(wrapper) { - var __method = this; - return function() { - return wrapper.apply(this, [__method.bind(this)].concat($A(arguments))); - } - }, - - methodize: function() { - if (this._methodized) return this._methodized; - var __method = this; - return this._methodized = function() { - return __method.apply(null, [this].concat($A(arguments))); - }; - } -}); - -Function.prototype.defer = Function.prototype.delay.curry(0.01); - -Date.prototype.toJSON = function() { - return '"' + this.getUTCFullYear() + '-' + - (this.getUTCMonth() + 1).toPaddedString(2) + '-' + - this.getUTCDate().toPaddedString(2) + 'T' + - this.getUTCHours().toPaddedString(2) + ':' + - this.getUTCMinutes().toPaddedString(2) + ':' + - this.getUTCSeconds().toPaddedString(2) + 'Z"'; -}; - -var Try = { - these: function() { - var returnValue; - - for (var i = 0, length = arguments.length; i < length; i++) { - var lambda = arguments[i]; - try { - returnValue = lambda(); - break; - } catch (e) { } - } - - return returnValue; - } -}; - -RegExp.prototype.match = RegExp.prototype.test; - -RegExp.escape = function(str) { - return String(str).replace(/([.*+?^=!:${}()|[\]\/\\])/g, '\\$1'); -}; - -/*--------------------------------------------------------------------------*/ - -var PeriodicalExecuter = Class.create({ - initialize: function(callback, frequency) { - this.callback = callback; - this.frequency = frequency; - this.currentlyExecuting = false; - - this.registerCallback(); - }, - - registerCallback: function() { - this.timer = setInterval(this.onTimerEvent.bind(this), this.frequency * 1000); - }, - - execute: function() { - this.callback(this); - }, - - stop: function() { - if (!this.timer) return; - clearInterval(this.timer); - this.timer = null; - }, - - onTimerEvent: function() { - if (!this.currentlyExecuting) { - try { - this.currentlyExecuting = true; - this.execute(); - } finally { - this.currentlyExecuting = false; - } - } - } -}); -Object.extend(String, { - interpret: function(value) { - return value == null ? '' : String(value); - }, - specialChar: { - '\b': '\\b', - '\t': '\\t', - '\n': '\\n', - '\f': '\\f', - '\r': '\\r', - '\\': '\\\\' - } -}); - -Object.extend(String.prototype, { - gsub: function(pattern, replacement) { - var result = '', source = this, match; - replacement = arguments.callee.prepareReplacement(replacement); - - while (source.length > 0) { - if (match = source.match(pattern)) { - result += source.slice(0, match.index); - result += String.interpret(replacement(match)); - source = source.slice(match.index + match[0].length); - } else { - result += source, source = ''; - } - } - return result; - }, - - sub: function(pattern, replacement, count) { - replacement = this.gsub.prepareReplacement(replacement); - count = Object.isUndefined(count) ? 1 : count; - - return this.gsub(pattern, function(match) { - if (--count < 0) return match[0]; - return replacement(match); - }); - }, - - scan: function(pattern, iterator) { - this.gsub(pattern, iterator); - return String(this); - }, - - truncate: function(length, truncation) { - length = length || 30; - truncation = Object.isUndefined(truncation) ? '...' : truncation; - return this.length > length ? - this.slice(0, length - truncation.length) + truncation : String(this); - }, - - strip: function() { - return this.replace(/^\s+/, '').replace(/\s+$/, ''); - }, - - stripTags: function() { - return this.replace(/<\/?[^>]+>/gi, ''); - }, - - stripScripts: function() { - return this.replace(new RegExp(Prototype.ScriptFragment, 'img'), ''); - }, - - extractScripts: function() { - var matchAll = new RegExp(Prototype.ScriptFragment, 'img'); - var matchOne = new RegExp(Prototype.ScriptFragment, 'im'); - return (this.match(matchAll) || []).map(function(scriptTag) { - return (scriptTag.match(matchOne) || ['', ''])[1]; - }); - }, - - evalScripts: function() { - return this.extractScripts().map(function(script) { return eval(script) }); - }, - - escapeHTML: function() { - var self = arguments.callee; - self.text.data = this; - return self.div.innerHTML; - }, - - unescapeHTML: function() { - var div = new Element('div'); - div.innerHTML = this.stripTags(); - return div.childNodes[0] ? (div.childNodes.length > 1 ? - $A(div.childNodes).inject('', function(memo, node) { return memo+node.nodeValue }) : - div.childNodes[0].nodeValue) : ''; - }, - - toQueryParams: function(separator) { - var match = this.strip().match(/([^?#]*)(#.*)?$/); - if (!match) return { }; - - return match[1].split(separator || '&').inject({ }, function(hash, pair) { - if ((pair = pair.split('='))[0]) { - var key = decodeURIComponent(pair.shift()); - var value = pair.length > 1 ? pair.join('=') : pair[0]; - if (value != undefined) value = decodeURIComponent(value); - - if (key in hash) { - if (!Object.isArray(hash[key])) hash[key] = [hash[key]]; - hash[key].push(value); - } - else hash[key] = value; - } - return hash; - }); - }, - - toArray: function() { - return this.split(''); - }, - - succ: function() { - return this.slice(0, this.length - 1) + - String.fromCharCode(this.charCodeAt(this.length - 1) + 1); - }, - - times: function(count) { - return count < 1 ? '' : new Array(count + 1).join(this); - }, - - camelize: function() { - var parts = this.split('-'), len = parts.length; - if (len == 1) return parts[0]; - - var camelized = this.charAt(0) == '-' - ? parts[0].charAt(0).toUpperCase() + parts[0].substring(1) - : parts[0]; - - for (var i = 1; i < len; i++) - camelized += parts[i].charAt(0).toUpperCase() + parts[i].substring(1); - - return camelized; - }, - - capitalize: function() { - return this.charAt(0).toUpperCase() + this.substring(1).toLowerCase(); - }, - - underscore: function() { - return this.gsub(/::/, '/').gsub(/([A-Z]+)([A-Z][a-z])/,'#{1}_#{2}').gsub(/([a-z\d])([A-Z])/,'#{1}_#{2}').gsub(/-/,'_').toLowerCase(); - }, - - dasherize: function() { - return this.gsub(/_/,'-'); - }, - - inspect: function(useDoubleQuotes) { - var escapedString = this.gsub(/[\x00-\x1f\\]/, function(match) { - var character = String.specialChar[match[0]]; - return character ? character : '\\u00' + match[0].charCodeAt().toPaddedString(2, 16); - }); - if (useDoubleQuotes) return '"' + escapedString.replace(/"/g, '\\"') + '"'; - return "'" + escapedString.replace(/'/g, '\\\'') + "'"; - }, - - toJSON: function() { - return this.inspect(true); - }, - - unfilterJSON: function(filter) { - return this.sub(filter || Prototype.JSONFilter, '#{1}'); - }, - - isJSON: function() { - var str = this; - if (str.blank()) return false; - str = this.replace(/\\./g, '@').replace(/"[^"\\\n\r]*"/g, ''); - return (/^[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t]*$/).test(str); - }, - - evalJSON: function(sanitize) { - var json = this.unfilterJSON(); - try { - if (!sanitize || json.isJSON()) return eval('(' + json + ')'); - } catch (e) { } - throw new SyntaxError('Badly formed JSON string: ' + this.inspect()); - }, - - include: function(pattern) { - return this.indexOf(pattern) > -1; - }, - - startsWith: function(pattern) { - return this.indexOf(pattern) === 0; - }, - - endsWith: function(pattern) { - var d = this.length - pattern.length; - return d >= 0 && this.lastIndexOf(pattern) === d; - }, - - empty: function() { - return this == ''; - }, - - blank: function() { - return /^\s*$/.test(this); - }, - - interpolate: function(object, pattern) { - return new Template(this, pattern).evaluate(object); - } -}); - -if (Prototype.Browser.WebKit || Prototype.Browser.IE) Object.extend(String.prototype, { - escapeHTML: function() { - return this.replace(/&/g,'&').replace(//g,'>'); - }, - unescapeHTML: function() { - return this.stripTags().replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>'); - } -}); - -String.prototype.gsub.prepareReplacement = function(replacement) { - if (Object.isFunction(replacement)) return replacement; - var template = new Template(replacement); - return function(match) { return template.evaluate(match) }; -}; - -String.prototype.parseQuery = String.prototype.toQueryParams; - -Object.extend(String.prototype.escapeHTML, { - div: document.createElement('div'), - text: document.createTextNode('') -}); - -String.prototype.escapeHTML.div.appendChild(String.prototype.escapeHTML.text); - -var Template = Class.create({ - initialize: function(template, pattern) { - this.template = template.toString(); - this.pattern = pattern || Template.Pattern; - }, - - evaluate: function(object) { - if (Object.isFunction(object.toTemplateReplacements)) - object = object.toTemplateReplacements(); - - return this.template.gsub(this.pattern, function(match) { - if (object == null) return ''; - - var before = match[1] || ''; - if (before == '\\') return match[2]; - - var ctx = object, expr = match[3]; - var pattern = /^([^.[]+|\[((?:.*?[^\\])?)\])(\.|\[|$)/; - match = pattern.exec(expr); - if (match == null) return before; - - while (match != null) { - var comp = match[1].startsWith('[') ? match[2].gsub('\\\\]', ']') : match[1]; - ctx = ctx[comp]; - if (null == ctx || '' == match[3]) break; - expr = expr.substring('[' == match[3] ? match[1].length : match[0].length); - match = pattern.exec(expr); - } - - return before + String.interpret(ctx); - }); - } -}); -Template.Pattern = /(^|.|\r|\n)(#\{(.*?)\})/; - -var $break = { }; - -var Enumerable = { - each: function(iterator, context) { - var index = 0; - try { - this._each(function(value) { - iterator.call(context, value, index++); - }); - } catch (e) { - if (e != $break) throw e; - } - return this; - }, - - eachSlice: function(number, iterator, context) { - var index = -number, slices = [], array = this.toArray(); - if (number < 1) return array; - while ((index += number) < array.length) - slices.push(array.slice(index, index+number)); - return slices.collect(iterator, context); - }, - - all: function(iterator, context) { - iterator = iterator || Prototype.K; - var result = true; - this.each(function(value, index) { - result = result && !!iterator.call(context, value, index); - if (!result) throw $break; - }); - return result; - }, - - any: function(iterator, context) { - iterator = iterator || Prototype.K; - var result = false; - this.each(function(value, index) { - if (result = !!iterator.call(context, value, index)) - throw $break; - }); - return result; - }, - - collect: function(iterator, context) { - iterator = iterator || Prototype.K; - var results = []; - this.each(function(value, index) { - results.push(iterator.call(context, value, index)); - }); - return results; - }, - - detect: function(iterator, context) { - var result; - this.each(function(value, index) { - if (iterator.call(context, value, index)) { - result = value; - throw $break; - } - }); - return result; - }, - - findAll: function(iterator, context) { - var results = []; - this.each(function(value, index) { - if (iterator.call(context, value, index)) - results.push(value); - }); - return results; - }, - - grep: function(filter, iterator, context) { - iterator = iterator || Prototype.K; - var results = []; - - if (Object.isString(filter)) - filter = new RegExp(filter); - - this.each(function(value, index) { - if (filter.match(value)) - results.push(iterator.call(context, value, index)); - }); - return results; - }, - - include: function(object) { - if (Object.isFunction(this.indexOf)) - if (this.indexOf(object) != -1) return true; - - var found = false; - this.each(function(value) { - if (value == object) { - found = true; - throw $break; - } - }); - return found; - }, - - inGroupsOf: function(number, fillWith) { - fillWith = Object.isUndefined(fillWith) ? null : fillWith; - return this.eachSlice(number, function(slice) { - while(slice.length < number) slice.push(fillWith); - return slice; - }); - }, - - inject: function(memo, iterator, context) { - this.each(function(value, index) { - memo = iterator.call(context, memo, value, index); - }); - return memo; - }, - - invoke: function(method) { - var args = $A(arguments).slice(1); - return this.map(function(value) { - return value[method].apply(value, args); - }); - }, - - max: function(iterator, context) { - iterator = iterator || Prototype.K; - var result; - this.each(function(value, index) { - value = iterator.call(context, value, index); - if (result == null || value >= result) - result = value; - }); - return result; - }, - - min: function(iterator, context) { - iterator = iterator || Prototype.K; - var result; - this.each(function(value, index) { - value = iterator.call(context, value, index); - if (result == null || value < result) - result = value; - }); - return result; - }, - - partition: function(iterator, context) { - iterator = iterator || Prototype.K; - var trues = [], falses = []; - this.each(function(value, index) { - (iterator.call(context, value, index) ? - trues : falses).push(value); - }); - return [trues, falses]; - }, - - pluck: function(property) { - var results = []; - this.each(function(value) { - results.push(value[property]); - }); - return results; - }, - - reject: function(iterator, context) { - var results = []; - this.each(function(value, index) { - if (!iterator.call(context, value, index)) - results.push(value); - }); - return results; - }, - - sortBy: function(iterator, context) { - return this.map(function(value, index) { - return { - value: value, - criteria: iterator.call(context, value, index) - }; - }).sort(function(left, right) { - var a = left.criteria, b = right.criteria; - return a < b ? -1 : a > b ? 1 : 0; - }).pluck('value'); - }, - - toArray: function() { - return this.map(); - }, - - zip: function() { - var iterator = Prototype.K, args = $A(arguments); - if (Object.isFunction(args.last())) - iterator = args.pop(); - - var collections = [this].concat(args).map($A); - return this.map(function(value, index) { - return iterator(collections.pluck(index)); - }); - }, - - size: function() { - return this.toArray().length; - }, - - inspect: function() { - return '#'; - } -}; - -Object.extend(Enumerable, { - map: Enumerable.collect, - find: Enumerable.detect, - select: Enumerable.findAll, - filter: Enumerable.findAll, - member: Enumerable.include, - entries: Enumerable.toArray, - every: Enumerable.all, - some: Enumerable.any -}); -function $A(iterable) { - if (!iterable) return []; - if (iterable.toArray) return iterable.toArray(); - var length = iterable.length || 0, results = new Array(length); - while (length--) results[length] = iterable[length]; - return results; -} - -if (Prototype.Browser.WebKit) { - $A = function(iterable) { - if (!iterable) return []; - if (!(Object.isFunction(iterable) && iterable == '[object NodeList]') && - iterable.toArray) return iterable.toArray(); - var length = iterable.length || 0, results = new Array(length); - while (length--) results[length] = iterable[length]; - return results; - }; -} - -Array.from = $A; - -Object.extend(Array.prototype, Enumerable); - -if (!Array.prototype._reverse) Array.prototype._reverse = Array.prototype.reverse; - -Object.extend(Array.prototype, { - _each: function(iterator) { - for (var i = 0, length = this.length; i < length; i++) - iterator(this[i]); - }, - - clear: function() { - this.length = 0; - return this; - }, - - first: function() { - return this[0]; - }, - - last: function() { - return this[this.length - 1]; - }, - - compact: function() { - return this.select(function(value) { - return value != null; - }); - }, - - flatten: function() { - return this.inject([], function(array, value) { - return array.concat(Object.isArray(value) ? - value.flatten() : [value]); - }); - }, - - without: function() { - var values = $A(arguments); - return this.select(function(value) { - return !values.include(value); - }); - }, - - reverse: function(inline) { - return (inline !== false ? this : this.toArray())._reverse(); - }, - - reduce: function() { - return this.length > 1 ? this : this[0]; - }, - - uniq: function(sorted) { - return this.inject([], function(array, value, index) { - if (0 == index || (sorted ? array.last() != value : !array.include(value))) - array.push(value); - return array; - }); - }, - - intersect: function(array) { - return this.uniq().findAll(function(item) { - return array.detect(function(value) { return item === value }); - }); - }, - - clone: function() { - return [].concat(this); - }, - - size: function() { - return this.length; - }, - - inspect: function() { - return '[' + this.map(Object.inspect).join(', ') + ']'; - }, - - toJSON: function() { - var results = []; - this.each(function(object) { - var value = Object.toJSON(object); - if (!Object.isUndefined(value)) results.push(value); - }); - return '[' + results.join(', ') + ']'; - } -}); - -// use native browser JS 1.6 implementation if available -if (Object.isFunction(Array.prototype.forEach)) - Array.prototype._each = Array.prototype.forEach; - -if (!Array.prototype.indexOf) Array.prototype.indexOf = function(item, i) { - i || (i = 0); - var length = this.length; - if (i < 0) i = length + i; - for (; i < length; i++) - if (this[i] === item) return i; - return -1; -}; - -if (!Array.prototype.lastIndexOf) Array.prototype.lastIndexOf = function(item, i) { - i = isNaN(i) ? this.length : (i < 0 ? this.length + i : i) + 1; - var n = this.slice(0, i).reverse().indexOf(item); - return (n < 0) ? n : i - n - 1; -}; - -Array.prototype.toArray = Array.prototype.clone; - -function $w(string) { - if (!Object.isString(string)) return []; - string = string.strip(); - return string ? string.split(/\s+/) : []; -} - -if (Prototype.Browser.Opera){ - Array.prototype.concat = function() { - var array = []; - for (var i = 0, length = this.length; i < length; i++) array.push(this[i]); - for (var i = 0, length = arguments.length; i < length; i++) { - if (Object.isArray(arguments[i])) { - for (var j = 0, arrayLength = arguments[i].length; j < arrayLength; j++) - array.push(arguments[i][j]); - } else { - array.push(arguments[i]); - } - } - return array; - }; -} -Object.extend(Number.prototype, { - toColorPart: function() { - return this.toPaddedString(2, 16); - }, - - succ: function() { - return this + 1; - }, - - times: function(iterator) { - $R(0, this, true).each(iterator); - return this; - }, - - toPaddedString: function(length, radix) { - var string = this.toString(radix || 10); - return '0'.times(length - string.length) + string; - }, - - toJSON: function() { - return isFinite(this) ? this.toString() : 'null'; - } -}); - -$w('abs round ceil floor').each(function(method){ - Number.prototype[method] = Math[method].methodize(); -}); -function $H(object) { - return new Hash(object); -}; - -var Hash = Class.create(Enumerable, (function() { - - function toQueryPair(key, value) { - if (Object.isUndefined(value)) return key; - return key + '=' + encodeURIComponent(String.interpret(value)); - } - - return { - initialize: function(object) { - this._object = Object.isHash(object) ? object.toObject() : Object.clone(object); - }, - - _each: function(iterator) { - for (var key in this._object) { - var value = this._object[key], pair = [key, value]; - pair.key = key; - pair.value = value; - iterator(pair); - } - }, - - set: function(key, value) { - return this._object[key] = value; - }, - - get: function(key) { - return this._object[key]; - }, - - unset: function(key) { - var value = this._object[key]; - delete this._object[key]; - return value; - }, - - toObject: function() { - return Object.clone(this._object); - }, - - keys: function() { - return this.pluck('key'); - }, - - values: function() { - return this.pluck('value'); - }, - - index: function(value) { - var match = this.detect(function(pair) { - return pair.value === value; - }); - return match && match.key; - }, - - merge: function(object) { - return this.clone().update(object); - }, - - update: function(object) { - return new Hash(object).inject(this, function(result, pair) { - result.set(pair.key, pair.value); - return result; - }); - }, - - toQueryString: function() { - return this.inject([], function(results, pair) { - var key = encodeURIComponent(pair.key), values = pair.value; - - if (values && typeof values == 'object') { - if (Object.isArray(values)) - return results.concat(values.map(toQueryPair.curry(key))); - } else results.push(toQueryPair(key, values)); - return results; - }).join('&'); - }, - - inspect: function() { - return '#'; - }, - - toJSON: function() { - return Object.toJSON(this.toObject()); - }, - - clone: function() { - return new Hash(this); - } - } -})()); - -Hash.prototype.toTemplateReplacements = Hash.prototype.toObject; -Hash.from = $H; -var ObjectRange = Class.create(Enumerable, { - initialize: function(start, end, exclusive) { - this.start = start; - this.end = end; - this.exclusive = exclusive; - }, - - _each: function(iterator) { - var value = this.start; - while (this.include(value)) { - iterator(value); - value = value.succ(); - } - }, - - include: function(value) { - if (value < this.start) - return false; - if (this.exclusive) - return value < this.end; - return value <= this.end; - } -}); - -var $R = function(start, end, exclusive) { - return new ObjectRange(start, end, exclusive); -}; - -var Ajax = { - getTransport: function() { - return Try.these( - function() {return new XMLHttpRequest()}, - function() {return new ActiveXObject('Msxml2.XMLHTTP')}, - function() {return new ActiveXObject('Microsoft.XMLHTTP')} - ) || false; - }, - - activeRequestCount: 0 -}; - -Ajax.Responders = { - responders: [], - - _each: function(iterator) { - this.responders._each(iterator); - }, - - register: function(responder) { - if (!this.include(responder)) - this.responders.push(responder); - }, - - unregister: function(responder) { - this.responders = this.responders.without(responder); - }, - - dispatch: function(callback, request, transport, json) { - this.each(function(responder) { - if (Object.isFunction(responder[callback])) { - try { - responder[callback].apply(responder, [request, transport, json]); - } catch (e) { } - } - }); - } -}; - -Object.extend(Ajax.Responders, Enumerable); - -Ajax.Responders.register({ - onCreate: function() { Ajax.activeRequestCount++ }, - onComplete: function() { Ajax.activeRequestCount-- } -}); - -Ajax.Base = Class.create({ - initialize: function(options) { - this.options = { - method: 'post', - asynchronous: true, - contentType: 'application/x-www-form-urlencoded', - encoding: 'UTF-8', - parameters: '', - evalJSON: true, - evalJS: true - }; - Object.extend(this.options, options || { }); - - this.options.method = this.options.method.toLowerCase(); - - if (Object.isString(this.options.parameters)) - this.options.parameters = this.options.parameters.toQueryParams(); - else if (Object.isHash(this.options.parameters)) - this.options.parameters = this.options.parameters.toObject(); - } -}); - -Ajax.Request = Class.create(Ajax.Base, { - _complete: false, - - initialize: function($super, url, options) { - $super(options); - this.transport = Ajax.getTransport(); - this.request(url); - }, - - request: function(url) { - this.url = url; - this.method = this.options.method; - var params = Object.clone(this.options.parameters); - - if (!['get', 'post'].include(this.method)) { - // simulate other verbs over post - params['_method'] = this.method; - this.method = 'post'; - } - - this.parameters = params; - - if (params = Object.toQueryString(params)) { - // when GET, append parameters to URL - if (this.method == 'get') - this.url += (this.url.include('?') ? '&' : '?') + params; - else if (/Konqueror|Safari|KHTML/.test(navigator.userAgent)) - params += '&_='; - } - - try { - var response = new Ajax.Response(this); - if (this.options.onCreate) this.options.onCreate(response); - Ajax.Responders.dispatch('onCreate', this, response); - - this.transport.open(this.method.toUpperCase(), this.url, - this.options.asynchronous); - - if (this.options.asynchronous) this.respondToReadyState.bind(this).defer(1); - - this.transport.onreadystatechange = this.onStateChange.bind(this); - this.setRequestHeaders(); - - this.body = this.method == 'post' ? (this.options.postBody || params) : null; - this.transport.send(this.body); - - /* Force Firefox to handle ready state 4 for synchronous requests */ - if (!this.options.asynchronous && this.transport.overrideMimeType) - this.onStateChange(); - - } - catch (e) { - this.dispatchException(e); - } - }, - - onStateChange: function() { - var readyState = this.transport.readyState; - if (readyState > 1 && !((readyState == 4) && this._complete)) - this.respondToReadyState(this.transport.readyState); - }, - - setRequestHeaders: function() { - var headers = { - 'X-Requested-With': 'XMLHttpRequest', - 'X-Prototype-Version': Prototype.Version, - 'Accept': 'text/javascript, text/html, application/xml, text/xml, */*' - }; - - if (this.method == 'post') { - headers['Content-type'] = this.options.contentType + - (this.options.encoding ? '; charset=' + this.options.encoding : ''); - - /* Force "Connection: close" for older Mozilla browsers to work - * around a bug where XMLHttpRequest sends an incorrect - * Content-length header. See Mozilla Bugzilla #246651. - */ - if (this.transport.overrideMimeType && - (navigator.userAgent.match(/Gecko\/(\d{4})/) || [0,2005])[1] < 2005) - headers['Connection'] = 'close'; - } - - // user-defined headers - if (typeof this.options.requestHeaders == 'object') { - var extras = this.options.requestHeaders; - - if (Object.isFunction(extras.push)) - for (var i = 0, length = extras.length; i < length; i += 2) - headers[extras[i]] = extras[i+1]; - else - $H(extras).each(function(pair) { headers[pair.key] = pair.value }); - } - - for (var name in headers) - this.transport.setRequestHeader(name, headers[name]); - }, - - success: function() { - var status = this.getStatus(); - return !status || (status >= 200 && status < 300); - }, - - getStatus: function() { - try { - return this.transport.status || 0; - } catch (e) { return 0 } - }, - - respondToReadyState: function(readyState) { - var state = Ajax.Request.Events[readyState], response = new Ajax.Response(this); - - if (state == 'Complete') { - try { - this._complete = true; - (this.options['on' + response.status] - || this.options['on' + (this.success() ? 'Success' : 'Failure')] - || Prototype.emptyFunction)(response, response.headerJSON); - } catch (e) { - this.dispatchException(e); - } - - var contentType = response.getHeader('Content-type'); - if (this.options.evalJS == 'force' - || (this.options.evalJS && this.isSameOrigin() && contentType - && contentType.match(/^\s*(text|application)\/(x-)?(java|ecma)script(;.*)?\s*$/i))) - this.evalResponse(); - } - - try { - (this.options['on' + state] || Prototype.emptyFunction)(response, response.headerJSON); - Ajax.Responders.dispatch('on' + state, this, response, response.headerJSON); - } catch (e) { - this.dispatchException(e); - } - - if (state == 'Complete') { - // avoid memory leak in MSIE: clean up - this.transport.onreadystatechange = Prototype.emptyFunction; - } - }, - - isSameOrigin: function() { - var m = this.url.match(/^\s*https?:\/\/[^\/]*/); - return !m || (m[0] == '#{protocol}//#{domain}#{port}'.interpolate({ - protocol: location.protocol, - domain: document.domain, - port: location.port ? ':' + location.port : '' - })); - }, - - getHeader: function(name) { - try { - return this.transport.getResponseHeader(name) || null; - } catch (e) { return null } - }, - - evalResponse: function() { - try { - return eval((this.transport.responseText || '').unfilterJSON()); - } catch (e) { - this.dispatchException(e); - } - }, - - dispatchException: function(exception) { - (this.options.onException || Prototype.emptyFunction)(this, exception); - Ajax.Responders.dispatch('onException', this, exception); - } -}); - -Ajax.Request.Events = - ['Uninitialized', 'Loading', 'Loaded', 'Interactive', 'Complete']; - -Ajax.Response = Class.create({ - initialize: function(request){ - this.request = request; - var transport = this.transport = request.transport, - readyState = this.readyState = transport.readyState; - - if((readyState > 2 && !Prototype.Browser.IE) || readyState == 4) { - this.status = this.getStatus(); - this.statusText = this.getStatusText(); - this.responseText = String.interpret(transport.responseText); - this.headerJSON = this._getHeaderJSON(); - } - - if(readyState == 4) { - var xml = transport.responseXML; - this.responseXML = Object.isUndefined(xml) ? null : xml; - this.responseJSON = this._getResponseJSON(); - } - }, - - status: 0, - statusText: '', - - getStatus: Ajax.Request.prototype.getStatus, - - getStatusText: function() { - try { - return this.transport.statusText || ''; - } catch (e) { return '' } - }, - - getHeader: Ajax.Request.prototype.getHeader, - - getAllHeaders: function() { - try { - return this.getAllResponseHeaders(); - } catch (e) { return null } - }, - - getResponseHeader: function(name) { - return this.transport.getResponseHeader(name); - }, - - getAllResponseHeaders: function() { - return this.transport.getAllResponseHeaders(); - }, - - _getHeaderJSON: function() { - var json = this.getHeader('X-JSON'); - if (!json) return null; - json = decodeURIComponent(escape(json)); - try { - return json.evalJSON(this.request.options.sanitizeJSON || - !this.request.isSameOrigin()); - } catch (e) { - this.request.dispatchException(e); - } - }, - - _getResponseJSON: function() { - var options = this.request.options; - if (!options.evalJSON || (options.evalJSON != 'force' && - !(this.getHeader('Content-type') || '').include('application/json')) || - this.responseText.blank()) - return null; - try { - return this.responseText.evalJSON(options.sanitizeJSON || - !this.request.isSameOrigin()); - } catch (e) { - this.request.dispatchException(e); - } - } -}); - -Ajax.Updater = Class.create(Ajax.Request, { - initialize: function($super, container, url, options) { - this.container = { - success: (container.success || container), - failure: (container.failure || (container.success ? null : container)) - }; - - options = Object.clone(options); - var onComplete = options.onComplete; - options.onComplete = (function(response, json) { - this.updateContent(response.responseText); - if (Object.isFunction(onComplete)) onComplete(response, json); - }).bind(this); - - $super(url, options); - }, - - updateContent: function(responseText) { - var receiver = this.container[this.success() ? 'success' : 'failure'], - options = this.options; - - if (!options.evalScripts) responseText = responseText.stripScripts(); - if (!$(receiver)) this.stop(); - - if (receiver = $(receiver)) { - if (options.insertion) { - if (Object.isString(options.insertion)) { - var insertion = { }; insertion[options.insertion] = responseText; - receiver.insert(insertion); - } - else options.insertion(receiver, responseText); - } - else receiver.update(responseText); - } - } -}); - -Ajax.PeriodicalUpdater = Class.create(Ajax.Base, { - initialize: function($super, container, url, options) { - $super(options); - this.onComplete = this.options.onComplete; - - this.frequency = (this.options.frequency || 2); - this.decay = (this.options.decay || 1); - - this.updater = { }; - this.container = container; - this.url = url; - - this.start(); - }, - - start: function() { - this.options.onComplete = this.updateComplete.bind(this); - this.onTimerEvent(); - }, - - stop: function() { - this.updater.options.onComplete = undefined; - clearTimeout(this.timer); - (this.onComplete || Prototype.emptyFunction).apply(this, arguments); - }, - - updateComplete: function(response) { - if (this.options.decay) { - this.decay = (response.responseText == this.lastText ? - this.decay * this.options.decay : 1); - - this.lastText = response.responseText; - } - this.timer = this.onTimerEvent.bind(this).delay(this.decay * this.frequency); - }, - - onTimerEvent: function() { - this.updater = new Ajax.Updater(this.container, this.url, this.options); - } -}); -function $(element) { - if (arguments.length > 1) { - for (var i = 0, elements = [], length = arguments.length; i < length; i++) - elements.push($(arguments[i])); - return elements; - } - if (Object.isString(element)) - element = document.getElementById(element); - return Element.extend(element); -} - -if (Prototype.BrowserFeatures.XPath) { - document._getElementsByXPath = function(expression, parentElement) { - var results = []; - var query = document.evaluate(expression, $(parentElement) || document, - null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null); - for (var i = 0, length = query.snapshotLength; i < length; i++) - results.push(Element.extend(query.snapshotItem(i))); - return results; - }; -} - -/*--------------------------------------------------------------------------*/ - -if (!window.Node) var Node = { }; - -if (!Node.ELEMENT_NODE) { - // DOM level 2 ECMAScript Language Binding - Object.extend(Node, { - ELEMENT_NODE: 1, - ATTRIBUTE_NODE: 2, - TEXT_NODE: 3, - CDATA_SECTION_NODE: 4, - ENTITY_REFERENCE_NODE: 5, - ENTITY_NODE: 6, - PROCESSING_INSTRUCTION_NODE: 7, - COMMENT_NODE: 8, - DOCUMENT_NODE: 9, - DOCUMENT_TYPE_NODE: 10, - DOCUMENT_FRAGMENT_NODE: 11, - NOTATION_NODE: 12 - }); -} - -(function() { - var element = this.Element; - this.Element = function(tagName, attributes) { - attributes = attributes || { }; - tagName = tagName.toLowerCase(); - var cache = Element.cache; - if (Prototype.Browser.IE && attributes.name) { - tagName = '<' + tagName + ' name="' + attributes.name + '">'; - delete attributes.name; - return Element.writeAttribute(document.createElement(tagName), attributes); - } - if (!cache[tagName]) cache[tagName] = Element.extend(document.createElement(tagName)); - return Element.writeAttribute(cache[tagName].cloneNode(false), attributes); - }; - Object.extend(this.Element, element || { }); - if (element) this.Element.prototype = element.prototype; -}).call(window); - -Element.cache = { }; - -Element.Methods = { - visible: function(element) { - return $(element).style.display != 'none'; - }, - - toggle: function(element) { - element = $(element); - Element[Element.visible(element) ? 'hide' : 'show'](element); - return element; - }, - - hide: function(element) { - $(element).style.display = 'none'; - return element; - }, - - show: function(element) { - $(element).style.display = ''; - return element; - }, - - remove: function(element) { - element = $(element); - element.parentNode.removeChild(element); - return element; - }, - - update: function(element, content) { - element = $(element); - if (content && content.toElement) content = content.toElement(); - if (Object.isElement(content)) return element.update().insert(content); - content = Object.toHTML(content); - element.innerHTML = content.stripScripts(); - content.evalScripts.bind(content).defer(); - return element; - }, - - replace: function(element, content) { - element = $(element); - if (content && content.toElement) content = content.toElement(); - else if (!Object.isElement(content)) { - content = Object.toHTML(content); - var range = element.ownerDocument.createRange(); - range.selectNode(element); - content.evalScripts.bind(content).defer(); - content = range.createContextualFragment(content.stripScripts()); - } - element.parentNode.replaceChild(content, element); - return element; - }, - - insert: function(element, insertions) { - element = $(element); - - if (Object.isString(insertions) || Object.isNumber(insertions) || - Object.isElement(insertions) || (insertions && (insertions.toElement || insertions.toHTML))) - insertions = {bottom:insertions}; - - var content, insert, tagName, childNodes; - - for (var position in insertions) { - content = insertions[position]; - position = position.toLowerCase(); - insert = Element._insertionTranslations[position]; - - if (content && content.toElement) content = content.toElement(); - if (Object.isElement(content)) { - insert(element, content); - continue; - } - - content = Object.toHTML(content); - - tagName = ((position == 'before' || position == 'after') - ? element.parentNode : element).tagName.toUpperCase(); - - childNodes = Element._getContentFromAnonymousElement(tagName, content.stripScripts()); - - if (position == 'top' || position == 'after') childNodes.reverse(); - childNodes.each(insert.curry(element)); - - content.evalScripts.bind(content).defer(); - } - - return element; - }, - - wrap: function(element, wrapper, attributes) { - element = $(element); - if (Object.isElement(wrapper)) - $(wrapper).writeAttribute(attributes || { }); - else if (Object.isString(wrapper)) wrapper = new Element(wrapper, attributes); - else wrapper = new Element('div', wrapper); - if (element.parentNode) - element.parentNode.replaceChild(wrapper, element); - wrapper.appendChild(element); - return wrapper; - }, - - inspect: function(element) { - element = $(element); - var result = '<' + element.tagName.toLowerCase(); - $H({'id': 'id', 'className': 'class'}).each(function(pair) { - var property = pair.first(), attribute = pair.last(); - var value = (element[property] || '').toString(); - if (value) result += ' ' + attribute + '=' + value.inspect(true); - }); - return result + '>'; - }, - - recursivelyCollect: function(element, property) { - element = $(element); - var elements = []; - while (element = element[property]) - if (element.nodeType == 1) - elements.push(Element.extend(element)); - return elements; - }, - - ancestors: function(element) { - return $(element).recursivelyCollect('parentNode'); - }, - - descendants: function(element) { - return $(element).select("*"); - }, - - firstDescendant: function(element) { - element = $(element).firstChild; - while (element && element.nodeType != 1) element = element.nextSibling; - return $(element); - }, - - immediateDescendants: function(element) { - if (!(element = $(element).firstChild)) return []; - while (element && element.nodeType != 1) element = element.nextSibling; - if (element) return [element].concat($(element).nextSiblings()); - return []; - }, - - previousSiblings: function(element) { - return $(element).recursivelyCollect('previousSibling'); - }, - - nextSiblings: function(element) { - return $(element).recursivelyCollect('nextSibling'); - }, - - siblings: function(element) { - element = $(element); - return element.previousSiblings().reverse().concat(element.nextSiblings()); - }, - - match: function(element, selector) { - if (Object.isString(selector)) - selector = new Selector(selector); - return selector.match($(element)); - }, - - up: function(element, expression, index) { - element = $(element); - if (arguments.length == 1) return $(element.parentNode); - var ancestors = element.ancestors(); - return Object.isNumber(expression) ? ancestors[expression] : - Selector.findElement(ancestors, expression, index); - }, - - down: function(element, expression, index) { - element = $(element); - if (arguments.length == 1) return element.firstDescendant(); - return Object.isNumber(expression) ? element.descendants()[expression] : - element.select(expression)[index || 0]; - }, - - previous: function(element, expression, index) { - element = $(element); - if (arguments.length == 1) return $(Selector.handlers.previousElementSibling(element)); - var previousSiblings = element.previousSiblings(); - return Object.isNumber(expression) ? previousSiblings[expression] : - Selector.findElement(previousSiblings, expression, index); - }, - - next: function(element, expression, index) { - element = $(element); - if (arguments.length == 1) return $(Selector.handlers.nextElementSibling(element)); - var nextSiblings = element.nextSiblings(); - return Object.isNumber(expression) ? nextSiblings[expression] : - Selector.findElement(nextSiblings, expression, index); - }, - - select: function() { - var args = $A(arguments), element = $(args.shift()); - return Selector.findChildElements(element, args); - }, - - adjacent: function() { - var args = $A(arguments), element = $(args.shift()); - return Selector.findChildElements(element.parentNode, args).without(element); - }, - - identify: function(element) { - element = $(element); - var id = element.readAttribute('id'), self = arguments.callee; - if (id) return id; - do { id = 'anonymous_element_' + self.counter++ } while ($(id)); - element.writeAttribute('id', id); - return id; - }, - - readAttribute: function(element, name) { - element = $(element); - if (Prototype.Browser.IE) { - var t = Element._attributeTranslations.read; - if (t.values[name]) return t.values[name](element, name); - if (t.names[name]) name = t.names[name]; - if (name.include(':')) { - return (!element.attributes || !element.attributes[name]) ? null : - element.attributes[name].value; - } - } - return element.getAttribute(name); - }, - - writeAttribute: function(element, name, value) { - element = $(element); - var attributes = { }, t = Element._attributeTranslations.write; - - if (typeof name == 'object') attributes = name; - else attributes[name] = Object.isUndefined(value) ? true : value; - - for (var attr in attributes) { - name = t.names[attr] || attr; - value = attributes[attr]; - if (t.values[attr]) name = t.values[attr](element, value); - if (value === false || value === null) - element.removeAttribute(name); - else if (value === true) - element.setAttribute(name, name); - else element.setAttribute(name, value); - } - return element; - }, - - getHeight: function(element) { - return $(element).getDimensions().height; - }, - - getWidth: function(element) { - return $(element).getDimensions().width; - }, - - classNames: function(element) { - return new Element.ClassNames(element); - }, - - hasClassName: function(element, className) { - if (!(element = $(element))) return; - var elementClassName = element.className; - return (elementClassName.length > 0 && (elementClassName == className || - new RegExp("(^|\\s)" + className + "(\\s|$)").test(elementClassName))); - }, - - addClassName: function(element, className) { - if (!(element = $(element))) return; - if (!element.hasClassName(className)) - element.className += (element.className ? ' ' : '') + className; - return element; - }, - - removeClassName: function(element, className) { - if (!(element = $(element))) return; - element.className = element.className.replace( - new RegExp("(^|\\s+)" + className + "(\\s+|$)"), ' ').strip(); - return element; - }, - - toggleClassName: function(element, className) { - if (!(element = $(element))) return; - return element[element.hasClassName(className) ? - 'removeClassName' : 'addClassName'](className); - }, - - // removes whitespace-only text node children - cleanWhitespace: function(element) { - element = $(element); - var node = element.firstChild; - while (node) { - var nextNode = node.nextSibling; - if (node.nodeType == 3 && !/\S/.test(node.nodeValue)) - element.removeChild(node); - node = nextNode; - } - return element; - }, - - empty: function(element) { - return $(element).innerHTML.blank(); - }, - - descendantOf: function(element, ancestor) { - element = $(element), ancestor = $(ancestor); - var originalAncestor = ancestor; - - if (element.compareDocumentPosition) - return (element.compareDocumentPosition(ancestor) & 8) === 8; - - if (element.sourceIndex && !Prototype.Browser.Opera) { - var e = element.sourceIndex, a = ancestor.sourceIndex, - nextAncestor = ancestor.nextSibling; - if (!nextAncestor) { - do { ancestor = ancestor.parentNode; } - while (!(nextAncestor = ancestor.nextSibling) && ancestor.parentNode); - } - if (nextAncestor && nextAncestor.sourceIndex) - return (e > a && e < nextAncestor.sourceIndex); - } - - while (element = element.parentNode) - if (element == originalAncestor) return true; - return false; - }, - - scrollTo: function(element) { - element = $(element); - var pos = element.cumulativeOffset(); - window.scrollTo(pos[0], pos[1]); - return element; - }, - - getStyle: function(element, style) { - element = $(element); - style = style == 'float' ? 'cssFloat' : style.camelize(); - var value = element.style[style]; - if (!value) { - var css = document.defaultView.getComputedStyle(element, null); - value = css ? css[style] : null; - } - if (style == 'opacity') return value ? parseFloat(value) : 1.0; - return value == 'auto' ? null : value; - }, - - getOpacity: function(element) { - return $(element).getStyle('opacity'); - }, - - setStyle: function(element, styles) { - element = $(element); - var elementStyle = element.style, match; - if (Object.isString(styles)) { - element.style.cssText += ';' + styles; - return styles.include('opacity') ? - element.setOpacity(styles.match(/opacity:\s*(\d?\.?\d*)/)[1]) : element; - } - for (var property in styles) - if (property == 'opacity') element.setOpacity(styles[property]); - else - elementStyle[(property == 'float' || property == 'cssFloat') ? - (Object.isUndefined(elementStyle.styleFloat) ? 'cssFloat' : 'styleFloat') : - property] = styles[property]; - - return element; - }, - - setOpacity: function(element, value) { - element = $(element); - element.style.opacity = (value == 1 || value === '') ? '' : - (value < 0.00001) ? 0 : value; - return element; - }, - - getDimensions: function(element) { - element = $(element); - var display = element.getStyle('display'); - if (display != 'none' && display != null) // Safari bug - return {width: element.offsetWidth, height: element.offsetHeight}; - - // All *Width and *Height properties give 0 on elements with display none, - // so enable the element temporarily - var els = element.style; - var originalVisibility = els.visibility; - var originalPosition = els.position; - var originalDisplay = els.display; - els.visibility = 'hidden'; - els.position = 'absolute'; - els.display = 'block'; - var originalWidth = element.clientWidth; - var originalHeight = element.clientHeight; - els.display = originalDisplay; - els.position = originalPosition; - els.visibility = originalVisibility; - return {width: originalWidth, height: originalHeight}; - }, - - makePositioned: function(element) { - element = $(element); - var pos = Element.getStyle(element, 'position'); - if (pos == 'static' || !pos) { - element._madePositioned = true; - element.style.position = 'relative'; - // Opera returns the offset relative to the positioning context, when an - // element is position relative but top and left have not been defined - if (window.opera) { - element.style.top = 0; - element.style.left = 0; - } - } - return element; - }, - - undoPositioned: function(element) { - element = $(element); - if (element._madePositioned) { - element._madePositioned = undefined; - element.style.position = - element.style.top = - element.style.left = - element.style.bottom = - element.style.right = ''; - } - return element; - }, - - makeClipping: function(element) { - element = $(element); - if (element._overflow) return element; - element._overflow = Element.getStyle(element, 'overflow') || 'auto'; - if (element._overflow !== 'hidden') - element.style.overflow = 'hidden'; - return element; - }, - - undoClipping: function(element) { - element = $(element); - if (!element._overflow) return element; - element.style.overflow = element._overflow == 'auto' ? '' : element._overflow; - element._overflow = null; - return element; - }, - - cumulativeOffset: function(element) { - var valueT = 0, valueL = 0; - do { - valueT += element.offsetTop || 0; - valueL += element.offsetLeft || 0; - element = element.offsetParent; - } while (element); - return Element._returnOffset(valueL, valueT); - }, - - positionedOffset: function(element) { - var valueT = 0, valueL = 0; - do { - valueT += element.offsetTop || 0; - valueL += element.offsetLeft || 0; - element = element.offsetParent; - if (element) { - if (element.tagName.toUpperCase() == 'BODY') break; - var p = Element.getStyle(element, 'position'); - if (p !== 'static') break; - } - } while (element); - return Element._returnOffset(valueL, valueT); - }, - - absolutize: function(element) { - element = $(element); - if (element.getStyle('position') == 'absolute') return element; - // Position.prepare(); // To be done manually by Scripty when it needs it. - - var offsets = element.positionedOffset(); - var top = offsets[1]; - var left = offsets[0]; - var width = element.clientWidth; - var height = element.clientHeight; - - element._originalLeft = left - parseFloat(element.style.left || 0); - element._originalTop = top - parseFloat(element.style.top || 0); - element._originalWidth = element.style.width; - element._originalHeight = element.style.height; - - element.style.position = 'absolute'; - element.style.top = top + 'px'; - element.style.left = left + 'px'; - element.style.width = width + 'px'; - element.style.height = height + 'px'; - return element; - }, - - relativize: function(element) { - element = $(element); - if (element.getStyle('position') == 'relative') return element; - // Position.prepare(); // To be done manually by Scripty when it needs it. - - element.style.position = 'relative'; - var top = parseFloat(element.style.top || 0) - (element._originalTop || 0); - var left = parseFloat(element.style.left || 0) - (element._originalLeft || 0); - - element.style.top = top + 'px'; - element.style.left = left + 'px'; - element.style.height = element._originalHeight; - element.style.width = element._originalWidth; - return element; - }, - - cumulativeScrollOffset: function(element) { - var valueT = 0, valueL = 0; - do { - valueT += element.scrollTop || 0; - valueL += element.scrollLeft || 0; - element = element.parentNode; - } while (element); - return Element._returnOffset(valueL, valueT); - }, - - getOffsetParent: function(element) { - if (element.offsetParent) return $(element.offsetParent); - if (element == document.body) return $(element); - - while ((element = element.parentNode) && element != document.body) - if (Element.getStyle(element, 'position') != 'static') - return $(element); - - return $(document.body); - }, - - viewportOffset: function(forElement) { - var valueT = 0, valueL = 0; - - var element = forElement; - do { - valueT += element.offsetTop || 0; - valueL += element.offsetLeft || 0; - - // Safari fix - if (element.offsetParent == document.body && - Element.getStyle(element, 'position') == 'absolute') break; - - } while (element = element.offsetParent); - - element = forElement; - do { - if (!Prototype.Browser.Opera || element.tagName.toUpperCase() == 'BODY') { - valueT -= element.scrollTop || 0; - valueL -= element.scrollLeft || 0; - } - } while (element = element.parentNode); - - return Element._returnOffset(valueL, valueT); - }, - - clonePosition: function(element, source) { - var options = Object.extend({ - setLeft: true, - setTop: true, - setWidth: true, - setHeight: true, - offsetTop: 0, - offsetLeft: 0 - }, arguments[2] || { }); - - // find page position of source - source = $(source); - var p = source.viewportOffset(); - - // find coordinate system to use - element = $(element); - var delta = [0, 0]; - var parent = null; - // delta [0,0] will do fine with position: fixed elements, - // position:absolute needs offsetParent deltas - if (Element.getStyle(element, 'position') == 'absolute') { - parent = element.getOffsetParent(); - delta = parent.viewportOffset(); - } - - // correct by body offsets (fixes Safari) - if (parent == document.body) { - delta[0] -= document.body.offsetLeft; - delta[1] -= document.body.offsetTop; - } - - // set position - if (options.setLeft) element.style.left = (p[0] - delta[0] + options.offsetLeft) + 'px'; - if (options.setTop) element.style.top = (p[1] - delta[1] + options.offsetTop) + 'px'; - if (options.setWidth) element.style.width = source.offsetWidth + 'px'; - if (options.setHeight) element.style.height = source.offsetHeight + 'px'; - return element; - } -}; - -Element.Methods.identify.counter = 1; - -Object.extend(Element.Methods, { - getElementsBySelector: Element.Methods.select, - childElements: Element.Methods.immediateDescendants -}); - -Element._attributeTranslations = { - write: { - names: { - className: 'class', - htmlFor: 'for' - }, - values: { } - } -}; - -if (Prototype.Browser.Opera) { - Element.Methods.getStyle = Element.Methods.getStyle.wrap( - function(proceed, element, style) { - switch (style) { - case 'left': case 'top': case 'right': case 'bottom': - if (proceed(element, 'position') === 'static') return null; - case 'height': case 'width': - // returns '0px' for hidden elements; we want it to return null - if (!Element.visible(element)) return null; - - // returns the border-box dimensions rather than the content-box - // dimensions, so we subtract padding and borders from the value - var dim = parseInt(proceed(element, style), 10); - - if (dim !== element['offset' + style.capitalize()]) - return dim + 'px'; - - var properties; - if (style === 'height') { - properties = ['border-top-width', 'padding-top', - 'padding-bottom', 'border-bottom-width']; - } - else { - properties = ['border-left-width', 'padding-left', - 'padding-right', 'border-right-width']; - } - return properties.inject(dim, function(memo, property) { - var val = proceed(element, property); - return val === null ? memo : memo - parseInt(val, 10); - }) + 'px'; - default: return proceed(element, style); - } - } - ); - - Element.Methods.readAttribute = Element.Methods.readAttribute.wrap( - function(proceed, element, attribute) { - if (attribute === 'title') return element.title; - return proceed(element, attribute); - } - ); -} - -else if (Prototype.Browser.IE) { - // IE doesn't report offsets correctly for static elements, so we change them - // to "relative" to get the values, then change them back. - Element.Methods.getOffsetParent = Element.Methods.getOffsetParent.wrap( - function(proceed, element) { - element = $(element); - // IE throws an error if element is not in document - try { element.offsetParent } - catch(e) { return $(document.body) } - var position = element.getStyle('position'); - if (position !== 'static') return proceed(element); - element.setStyle({ position: 'relative' }); - var value = proceed(element); - element.setStyle({ position: position }); - return value; - } - ); - - $w('positionedOffset viewportOffset').each(function(method) { - Element.Methods[method] = Element.Methods[method].wrap( - function(proceed, element) { - element = $(element); - try { element.offsetParent } - catch(e) { return Element._returnOffset(0,0) } - var position = element.getStyle('position'); - if (position !== 'static') return proceed(element); - // Trigger hasLayout on the offset parent so that IE6 reports - // accurate offsetTop and offsetLeft values for position: fixed. - var offsetParent = element.getOffsetParent(); - if (offsetParent && offsetParent.getStyle('position') === 'fixed') - offsetParent.setStyle({ zoom: 1 }); - element.setStyle({ position: 'relative' }); - var value = proceed(element); - element.setStyle({ position: position }); - return value; - } - ); - }); - - Element.Methods.cumulativeOffset = Element.Methods.cumulativeOffset.wrap( - function(proceed, element) { - try { element.offsetParent } - catch(e) { return Element._returnOffset(0,0) } - return proceed(element); - } - ); - - Element.Methods.getStyle = function(element, style) { - element = $(element); - style = (style == 'float' || style == 'cssFloat') ? 'styleFloat' : style.camelize(); - var value = element.style[style]; - if (!value && element.currentStyle) value = element.currentStyle[style]; - - if (style == 'opacity') { - if (value = (element.getStyle('filter') || '').match(/alpha\(opacity=(.*)\)/)) - if (value[1]) return parseFloat(value[1]) / 100; - return 1.0; - } - - if (value == 'auto') { - if ((style == 'width' || style == 'height') && (element.getStyle('display') != 'none')) - return element['offset' + style.capitalize()] + 'px'; - return null; - } - return value; - }; - - Element.Methods.setOpacity = function(element, value) { - function stripAlpha(filter){ - return filter.replace(/alpha\([^\)]*\)/gi,''); - } - element = $(element); - var currentStyle = element.currentStyle; - if ((currentStyle && !currentStyle.hasLayout) || - (!currentStyle && element.style.zoom == 'normal')) - element.style.zoom = 1; - - var filter = element.getStyle('filter'), style = element.style; - if (value == 1 || value === '') { - (filter = stripAlpha(filter)) ? - style.filter = filter : style.removeAttribute('filter'); - return element; - } else if (value < 0.00001) value = 0; - style.filter = stripAlpha(filter) + - 'alpha(opacity=' + (value * 100) + ')'; - return element; - }; - - Element._attributeTranslations = { - read: { - names: { - 'class': 'className', - 'for': 'htmlFor' - }, - values: { - _getAttr: function(element, attribute) { - return element.getAttribute(attribute, 2); - }, - _getAttrNode: function(element, attribute) { - var node = element.getAttributeNode(attribute); - return node ? node.value : ""; - }, - _getEv: function(element, attribute) { - attribute = element.getAttribute(attribute); - return attribute ? attribute.toString().slice(23, -2) : null; - }, - _flag: function(element, attribute) { - return $(element).hasAttribute(attribute) ? attribute : null; - }, - style: function(element) { - return element.style.cssText.toLowerCase(); - }, - title: function(element) { - return element.title; - } - } - } - }; - - Element._attributeTranslations.write = { - names: Object.extend({ - cellpadding: 'cellPadding', - cellspacing: 'cellSpacing' - }, Element._attributeTranslations.read.names), - values: { - checked: function(element, value) { - element.checked = !!value; - }, - - style: function(element, value) { - element.style.cssText = value ? value : ''; - } - } - }; - - Element._attributeTranslations.has = {}; - - $w('colSpan rowSpan vAlign dateTime accessKey tabIndex ' + - 'encType maxLength readOnly longDesc frameBorder').each(function(attr) { - Element._attributeTranslations.write.names[attr.toLowerCase()] = attr; - Element._attributeTranslations.has[attr.toLowerCase()] = attr; - }); - - (function(v) { - Object.extend(v, { - href: v._getAttr, - src: v._getAttr, - type: v._getAttr, - action: v._getAttrNode, - disabled: v._flag, - checked: v._flag, - readonly: v._flag, - multiple: v._flag, - onload: v._getEv, - onunload: v._getEv, - onclick: v._getEv, - ondblclick: v._getEv, - onmousedown: v._getEv, - onmouseup: v._getEv, - onmouseover: v._getEv, - onmousemove: v._getEv, - onmouseout: v._getEv, - onfocus: v._getEv, - onblur: v._getEv, - onkeypress: v._getEv, - onkeydown: v._getEv, - onkeyup: v._getEv, - onsubmit: v._getEv, - onreset: v._getEv, - onselect: v._getEv, - onchange: v._getEv - }); - })(Element._attributeTranslations.read.values); -} - -else if (Prototype.Browser.Gecko && /rv:1\.8\.0/.test(navigator.userAgent)) { - Element.Methods.setOpacity = function(element, value) { - element = $(element); - element.style.opacity = (value == 1) ? 0.999999 : - (value === '') ? '' : (value < 0.00001) ? 0 : value; - return element; - }; -} - -else if (Prototype.Browser.WebKit) { - Element.Methods.setOpacity = function(element, value) { - element = $(element); - element.style.opacity = (value == 1 || value === '') ? '' : - (value < 0.00001) ? 0 : value; - - if (value == 1) - if(element.tagName.toUpperCase() == 'IMG' && element.width) { - element.width++; element.width--; - } else try { - var n = document.createTextNode(' '); - element.appendChild(n); - element.removeChild(n); - } catch (e) { } - - return element; - }; - - // Safari returns margins on body which is incorrect if the child is absolutely - // positioned. For performance reasons, redefine Element#cumulativeOffset for - // KHTML/WebKit only. - Element.Methods.cumulativeOffset = function(element) { - var valueT = 0, valueL = 0; - do { - valueT += element.offsetTop || 0; - valueL += element.offsetLeft || 0; - if (element.offsetParent == document.body) - if (Element.getStyle(element, 'position') == 'absolute') break; - - element = element.offsetParent; - } while (element); - - return Element._returnOffset(valueL, valueT); - }; -} - -if (Prototype.Browser.IE || Prototype.Browser.Opera) { - // IE and Opera are missing .innerHTML support for TABLE-related and SELECT elements - Element.Methods.update = function(element, content) { - element = $(element); - - if (content && content.toElement) content = content.toElement(); - if (Object.isElement(content)) return element.update().insert(content); - - content = Object.toHTML(content); - var tagName = element.tagName.toUpperCase(); - - if (tagName in Element._insertionTranslations.tags) { - $A(element.childNodes).each(function(node) { element.removeChild(node) }); - Element._getContentFromAnonymousElement(tagName, content.stripScripts()) - .each(function(node) { element.appendChild(node) }); - } - else element.innerHTML = content.stripScripts(); - - content.evalScripts.bind(content).defer(); - return element; - }; -} - -if ('outerHTML' in document.createElement('div')) { - Element.Methods.replace = function(element, content) { - element = $(element); - - if (content && content.toElement) content = content.toElement(); - if (Object.isElement(content)) { - element.parentNode.replaceChild(content, element); - return element; - } - - content = Object.toHTML(content); - var parent = element.parentNode, tagName = parent.tagName.toUpperCase(); - - if (Element._insertionTranslations.tags[tagName]) { - var nextSibling = element.next(); - var fragments = Element._getContentFromAnonymousElement(tagName, content.stripScripts()); - parent.removeChild(element); - if (nextSibling) - fragments.each(function(node) { parent.insertBefore(node, nextSibling) }); - else - fragments.each(function(node) { parent.appendChild(node) }); - } - else element.outerHTML = content.stripScripts(); - - content.evalScripts.bind(content).defer(); - return element; - }; -} - -Element._returnOffset = function(l, t) { - var result = [l, t]; - result.left = l; - result.top = t; - return result; -}; - -Element._getContentFromAnonymousElement = function(tagName, html) { - var div = new Element('div'), t = Element._insertionTranslations.tags[tagName]; - if (t) { - div.innerHTML = t[0] + html + t[1]; - t[2].times(function() { div = div.firstChild }); - } else div.innerHTML = html; - return $A(div.childNodes); -}; - -Element._insertionTranslations = { - before: function(element, node) { - element.parentNode.insertBefore(node, element); - }, - top: function(element, node) { - element.insertBefore(node, element.firstChild); - }, - bottom: function(element, node) { - element.appendChild(node); - }, - after: function(element, node) { - element.parentNode.insertBefore(node, element.nextSibling); - }, - tags: { - TABLE: ['', '
    ', 1], - TBODY: ['', '
    ', 2], - TR: ['', '
    ', 3], - TD: ['
    ', '
    ', 4], - SELECT: ['', 1] - } -}; - -(function() { - Object.extend(this.tags, { - THEAD: this.tags.TBODY, - TFOOT: this.tags.TBODY, - TH: this.tags.TD - }); -}).call(Element._insertionTranslations); - -Element.Methods.Simulated = { - hasAttribute: function(element, attribute) { - attribute = Element._attributeTranslations.has[attribute] || attribute; - var node = $(element).getAttributeNode(attribute); - return node && node.specified; - } -}; - -Element.Methods.ByTag = { }; - -Object.extend(Element, Element.Methods); - -if (!Prototype.BrowserFeatures.ElementExtensions && - document.createElement('div').__proto__) { - window.HTMLElement = { }; - window.HTMLElement.prototype = document.createElement('div').__proto__; - Prototype.BrowserFeatures.ElementExtensions = true; -} - -Element.extend = (function() { - if (Prototype.BrowserFeatures.SpecificElementExtensions) - return Prototype.K; - - var Methods = { }, ByTag = Element.Methods.ByTag; - - var extend = Object.extend(function(element) { - if (!element || element._extendedByPrototype || - element.nodeType != 1 || element == window) return element; - - var methods = Object.clone(Methods), - tagName = element.tagName.toUpperCase(), property, value; - - // extend methods for specific tags - if (ByTag[tagName]) Object.extend(methods, ByTag[tagName]); - - for (property in methods) { - value = methods[property]; - if (Object.isFunction(value) && !(property in element)) - element[property] = value.methodize(); - } - - element._extendedByPrototype = Prototype.emptyFunction; - return element; - - }, { - refresh: function() { - // extend methods for all tags (Safari doesn't need this) - if (!Prototype.BrowserFeatures.ElementExtensions) { - Object.extend(Methods, Element.Methods); - Object.extend(Methods, Element.Methods.Simulated); - } - } - }); - - extend.refresh(); - return extend; -})(); - -Element.hasAttribute = function(element, attribute) { - if (element.hasAttribute) return element.hasAttribute(attribute); - return Element.Methods.Simulated.hasAttribute(element, attribute); -}; - -Element.addMethods = function(methods) { - var F = Prototype.BrowserFeatures, T = Element.Methods.ByTag; - - if (!methods) { - Object.extend(Form, Form.Methods); - Object.extend(Form.Element, Form.Element.Methods); - Object.extend(Element.Methods.ByTag, { - "FORM": Object.clone(Form.Methods), - "INPUT": Object.clone(Form.Element.Methods), - "SELECT": Object.clone(Form.Element.Methods), - "TEXTAREA": Object.clone(Form.Element.Methods) - }); - } - - if (arguments.length == 2) { - var tagName = methods; - methods = arguments[1]; - } - - if (!tagName) Object.extend(Element.Methods, methods || { }); - else { - if (Object.isArray(tagName)) tagName.each(extend); - else extend(tagName); - } - - function extend(tagName) { - tagName = tagName.toUpperCase(); - if (!Element.Methods.ByTag[tagName]) - Element.Methods.ByTag[tagName] = { }; - Object.extend(Element.Methods.ByTag[tagName], methods); - } - - function copy(methods, destination, onlyIfAbsent) { - onlyIfAbsent = onlyIfAbsent || false; - for (var property in methods) { - var value = methods[property]; - if (!Object.isFunction(value)) continue; - if (!onlyIfAbsent || !(property in destination)) - destination[property] = value.methodize(); - } - } - - function findDOMClass(tagName) { - var klass; - var trans = { - "OPTGROUP": "OptGroup", "TEXTAREA": "TextArea", "P": "Paragraph", - "FIELDSET": "FieldSet", "UL": "UList", "OL": "OList", "DL": "DList", - "DIR": "Directory", "H1": "Heading", "H2": "Heading", "H3": "Heading", - "H4": "Heading", "H5": "Heading", "H6": "Heading", "Q": "Quote", - "INS": "Mod", "DEL": "Mod", "A": "Anchor", "IMG": "Image", "CAPTION": - "TableCaption", "COL": "TableCol", "COLGROUP": "TableCol", "THEAD": - "TableSection", "TFOOT": "TableSection", "TBODY": "TableSection", "TR": - "TableRow", "TH": "TableCell", "TD": "TableCell", "FRAMESET": - "FrameSet", "IFRAME": "IFrame" - }; - if (trans[tagName]) klass = 'HTML' + trans[tagName] + 'Element'; - if (window[klass]) return window[klass]; - klass = 'HTML' + tagName + 'Element'; - if (window[klass]) return window[klass]; - klass = 'HTML' + tagName.capitalize() + 'Element'; - if (window[klass]) return window[klass]; - - window[klass] = { }; - window[klass].prototype = document.createElement(tagName).__proto__; - return window[klass]; - } - - if (F.ElementExtensions) { - copy(Element.Methods, HTMLElement.prototype); - copy(Element.Methods.Simulated, HTMLElement.prototype, true); - } - - if (F.SpecificElementExtensions) { - for (var tag in Element.Methods.ByTag) { - var klass = findDOMClass(tag); - if (Object.isUndefined(klass)) continue; - copy(T[tag], klass.prototype); - } - } - - Object.extend(Element, Element.Methods); - delete Element.ByTag; - - if (Element.extend.refresh) Element.extend.refresh(); - Element.cache = { }; -}; - -document.viewport = { - getDimensions: function() { - var dimensions = { }; - var B = Prototype.Browser; - $w('width height').each(function(d) { - var D = d.capitalize(); - dimensions[d] = (B.WebKit && !document.evaluate) ? self['inner' + D] : - (B.Opera) ? document.body['client' + D] : document.documentElement['client' + D]; - }); - return dimensions; - }, - - getWidth: function() { - return this.getDimensions().width; - }, - - getHeight: function() { - return this.getDimensions().height; - }, - - getScrollOffsets: function() { - return Element._returnOffset( - window.pageXOffset || document.documentElement.scrollLeft || document.body.scrollLeft, - window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop); - } -}; -/* Portions of the Selector class are derived from Jack Slocum's DomQuery, - * part of YUI-Ext version 0.40, distributed under the terms of an MIT-style - * license. Please see http://www.yui-ext.com/ for more information. */ - -var Selector = Class.create({ - initialize: function(expression) { - this.expression = expression.strip(); - this.compileMatcher(); - }, - - shouldUseXPath: function() { - if (!Prototype.BrowserFeatures.XPath) return false; - - var e = this.expression; - - // Safari 3 chokes on :*-of-type and :empty - if (Prototype.Browser.WebKit && - (e.include("-of-type") || e.include(":empty"))) - return false; - - // XPath can't do namespaced attributes, nor can it read - // the "checked" property from DOM nodes - if ((/(\[[\w-]*?:|:checked)/).test(this.expression)) - return false; - - return true; - }, - - compileMatcher: function() { - if (this.shouldUseXPath()) - return this.compileXPathMatcher(); - - var e = this.expression, ps = Selector.patterns, h = Selector.handlers, - c = Selector.criteria, le, p, m; - - if (Selector._cache[e]) { - this.matcher = Selector._cache[e]; - return; - } - - this.matcher = ["this.matcher = function(root) {", - "var r = root, h = Selector.handlers, c = false, n;"]; - - while (e && le != e && (/\S/).test(e)) { - le = e; - for (var i in ps) { - p = ps[i]; - if (m = e.match(p)) { - this.matcher.push(Object.isFunction(c[i]) ? c[i](m) : - new Template(c[i]).evaluate(m)); - e = e.replace(m[0], ''); - break; - } - } - } - - this.matcher.push("return h.unique(n);\n}"); - eval(this.matcher.join('\n')); - Selector._cache[this.expression] = this.matcher; - }, - - compileXPathMatcher: function() { - var e = this.expression, ps = Selector.patterns, - x = Selector.xpath, le, m; - - if (Selector._cache[e]) { - this.xpath = Selector._cache[e]; return; - } - - this.matcher = ['.//*']; - while (e && le != e && (/\S/).test(e)) { - le = e; - for (var i in ps) { - if (m = e.match(ps[i])) { - this.matcher.push(Object.isFunction(x[i]) ? x[i](m) : - new Template(x[i]).evaluate(m)); - e = e.replace(m[0], ''); - break; - } - } - } - - this.xpath = this.matcher.join(''); - Selector._cache[this.expression] = this.xpath; - }, - - findElements: function(root) { - root = root || document; - if (this.xpath) return document._getElementsByXPath(this.xpath, root); - return this.matcher(root); - }, - - match: function(element) { - this.tokens = []; - - var e = this.expression, ps = Selector.patterns, as = Selector.assertions; - var le, p, m; - - while (e && le !== e && (/\S/).test(e)) { - le = e; - for (var i in ps) { - p = ps[i]; - if (m = e.match(p)) { - // use the Selector.assertions methods unless the selector - // is too complex. - if (as[i]) { - this.tokens.push([i, Object.clone(m)]); - e = e.replace(m[0], ''); - } else { - // reluctantly do a document-wide search - // and look for a match in the array - return this.findElements(document).include(element); - } - } - } - } - - var match = true, name, matches; - for (var i = 0, token; token = this.tokens[i]; i++) { - name = token[0], matches = token[1]; - if (!Selector.assertions[name](element, matches)) { - match = false; break; - } - } - - return match; - }, - - toString: function() { - return this.expression; - }, - - inspect: function() { - return "#"; - } -}); - -Object.extend(Selector, { - _cache: { }, - - xpath: { - descendant: "//*", - child: "/*", - adjacent: "/following-sibling::*[1]", - laterSibling: '/following-sibling::*', - tagName: function(m) { - if (m[1] == '*') return ''; - return "[local-name()='" + m[1].toLowerCase() + - "' or local-name()='" + m[1].toUpperCase() + "']"; - }, - className: "[contains(concat(' ', @class, ' '), ' #{1} ')]", - id: "[@id='#{1}']", - attrPresence: function(m) { - m[1] = m[1].toLowerCase(); - return new Template("[@#{1}]").evaluate(m); - }, - attr: function(m) { - m[1] = m[1].toLowerCase(); - m[3] = m[5] || m[6]; - return new Template(Selector.xpath.operators[m[2]]).evaluate(m); - }, - pseudo: function(m) { - var h = Selector.xpath.pseudos[m[1]]; - if (!h) return ''; - if (Object.isFunction(h)) return h(m); - return new Template(Selector.xpath.pseudos[m[1]]).evaluate(m); - }, - operators: { - '=': "[@#{1}='#{3}']", - '!=': "[@#{1}!='#{3}']", - '^=': "[starts-with(@#{1}, '#{3}')]", - '$=': "[substring(@#{1}, (string-length(@#{1}) - string-length('#{3}') + 1))='#{3}']", - '*=': "[contains(@#{1}, '#{3}')]", - '~=': "[contains(concat(' ', @#{1}, ' '), ' #{3} ')]", - '|=': "[contains(concat('-', @#{1}, '-'), '-#{3}-')]" - }, - pseudos: { - 'first-child': '[not(preceding-sibling::*)]', - 'last-child': '[not(following-sibling::*)]', - 'only-child': '[not(preceding-sibling::* or following-sibling::*)]', - 'empty': "[count(*) = 0 and (count(text()) = 0 or translate(text(), ' \t\r\n', '') = '')]", - 'checked': "[@checked]", - 'disabled': "[@disabled]", - 'enabled': "[not(@disabled)]", - 'not': function(m) { - var e = m[6], p = Selector.patterns, - x = Selector.xpath, le, v; - - var exclusion = []; - while (e && le != e && (/\S/).test(e)) { - le = e; - for (var i in p) { - if (m = e.match(p[i])) { - v = Object.isFunction(x[i]) ? x[i](m) : new Template(x[i]).evaluate(m); - exclusion.push("(" + v.substring(1, v.length - 1) + ")"); - e = e.replace(m[0], ''); - break; - } - } - } - return "[not(" + exclusion.join(" and ") + ")]"; - }, - 'nth-child': function(m) { - return Selector.xpath.pseudos.nth("(count(./preceding-sibling::*) + 1) ", m); - }, - 'nth-last-child': function(m) { - return Selector.xpath.pseudos.nth("(count(./following-sibling::*) + 1) ", m); - }, - 'nth-of-type': function(m) { - return Selector.xpath.pseudos.nth("position() ", m); - }, - 'nth-last-of-type': function(m) { - return Selector.xpath.pseudos.nth("(last() + 1 - position()) ", m); - }, - 'first-of-type': function(m) { - m[6] = "1"; return Selector.xpath.pseudos['nth-of-type'](m); - }, - 'last-of-type': function(m) { - m[6] = "1"; return Selector.xpath.pseudos['nth-last-of-type'](m); - }, - 'only-of-type': function(m) { - var p = Selector.xpath.pseudos; return p['first-of-type'](m) + p['last-of-type'](m); - }, - nth: function(fragment, m) { - var mm, formula = m[6], predicate; - if (formula == 'even') formula = '2n+0'; - if (formula == 'odd') formula = '2n+1'; - if (mm = formula.match(/^(\d+)$/)) // digit only - return '[' + fragment + "= " + mm[1] + ']'; - if (mm = formula.match(/^(-?\d*)?n(([+-])(\d+))?/)) { // an+b - if (mm[1] == "-") mm[1] = -1; - var a = mm[1] ? Number(mm[1]) : 1; - var b = mm[2] ? Number(mm[2]) : 0; - predicate = "[((#{fragment} - #{b}) mod #{a} = 0) and " + - "((#{fragment} - #{b}) div #{a} >= 0)]"; - return new Template(predicate).evaluate({ - fragment: fragment, a: a, b: b }); - } - } - } - }, - - criteria: { - tagName: 'n = h.tagName(n, r, "#{1}", c); c = false;', - className: 'n = h.className(n, r, "#{1}", c); c = false;', - id: 'n = h.id(n, r, "#{1}", c); c = false;', - attrPresence: 'n = h.attrPresence(n, r, "#{1}", c); c = false;', - attr: function(m) { - m[3] = (m[5] || m[6]); - return new Template('n = h.attr(n, r, "#{1}", "#{3}", "#{2}", c); c = false;').evaluate(m); - }, - pseudo: function(m) { - if (m[6]) m[6] = m[6].replace(/"/g, '\\"'); - return new Template('n = h.pseudo(n, "#{1}", "#{6}", r, c); c = false;').evaluate(m); - }, - descendant: 'c = "descendant";', - child: 'c = "child";', - adjacent: 'c = "adjacent";', - laterSibling: 'c = "laterSibling";' - }, - - patterns: { - // combinators must be listed first - // (and descendant needs to be last combinator) - laterSibling: /^\s*~\s*/, - child: /^\s*>\s*/, - adjacent: /^\s*\+\s*/, - descendant: /^\s/, - - // selectors follow - tagName: /^\s*(\*|[\w\-]+)(\b|$)?/, - id: /^#([\w\-\*]+)(\b|$)/, - className: /^\.([\w\-\*]+)(\b|$)/, - pseudo: -/^:((first|last|nth|nth-last|only)(-child|-of-type)|empty|checked|(en|dis)abled|not)(\((.*?)\))?(\b|$|(?=\s|[:+~>]))/, - attrPresence: /^\[((?:[\w]+:)?[\w]+)\]/, - attr: /\[((?:[\w-]*:)?[\w-]+)\s*(?:([!^$*~|]?=)\s*((['"])([^\4]*?)\4|([^'"][^\]]*?)))?\]/ - }, - - // for Selector.match and Element#match - assertions: { - tagName: function(element, matches) { - return matches[1].toUpperCase() == element.tagName.toUpperCase(); - }, - - className: function(element, matches) { - return Element.hasClassName(element, matches[1]); - }, - - id: function(element, matches) { - return element.id === matches[1]; - }, - - attrPresence: function(element, matches) { - return Element.hasAttribute(element, matches[1]); - }, - - attr: function(element, matches) { - var nodeValue = Element.readAttribute(element, matches[1]); - return nodeValue && Selector.operators[matches[2]](nodeValue, matches[5] || matches[6]); - } - }, - - handlers: { - // UTILITY FUNCTIONS - // joins two collections - concat: function(a, b) { - for (var i = 0, node; node = b[i]; i++) - a.push(node); - return a; - }, - - // marks an array of nodes for counting - mark: function(nodes) { - var _true = Prototype.emptyFunction; - for (var i = 0, node; node = nodes[i]; i++) - node._countedByPrototype = _true; - return nodes; - }, - - unmark: function(nodes) { - for (var i = 0, node; node = nodes[i]; i++) - node._countedByPrototype = undefined; - return nodes; - }, - - // mark each child node with its position (for nth calls) - // "ofType" flag indicates whether we're indexing for nth-of-type - // rather than nth-child - index: function(parentNode, reverse, ofType) { - parentNode._countedByPrototype = Prototype.emptyFunction; - if (reverse) { - for (var nodes = parentNode.childNodes, i = nodes.length - 1, j = 1; i >= 0; i--) { - var node = nodes[i]; - if (node.nodeType == 1 && (!ofType || node._countedByPrototype)) node.nodeIndex = j++; - } - } else { - for (var i = 0, j = 1, nodes = parentNode.childNodes; node = nodes[i]; i++) - if (node.nodeType == 1 && (!ofType || node._countedByPrototype)) node.nodeIndex = j++; - } - }, - - // filters out duplicates and extends all nodes - unique: function(nodes) { - if (nodes.length == 0) return nodes; - var results = [], n; - for (var i = 0, l = nodes.length; i < l; i++) - if (!(n = nodes[i])._countedByPrototype) { - n._countedByPrototype = Prototype.emptyFunction; - results.push(Element.extend(n)); - } - return Selector.handlers.unmark(results); - }, - - // COMBINATOR FUNCTIONS - descendant: function(nodes) { - var h = Selector.handlers; - for (var i = 0, results = [], node; node = nodes[i]; i++) - h.concat(results, node.getElementsByTagName('*')); - return results; - }, - - child: function(nodes) { - var h = Selector.handlers; - for (var i = 0, results = [], node; node = nodes[i]; i++) { - for (var j = 0, child; child = node.childNodes[j]; j++) - if (child.nodeType == 1 && child.tagName != '!') results.push(child); - } - return results; - }, - - adjacent: function(nodes) { - for (var i = 0, results = [], node; node = nodes[i]; i++) { - var next = this.nextElementSibling(node); - if (next) results.push(next); - } - return results; - }, - - laterSibling: function(nodes) { - var h = Selector.handlers; - for (var i = 0, results = [], node; node = nodes[i]; i++) - h.concat(results, Element.nextSiblings(node)); - return results; - }, - - nextElementSibling: function(node) { - while (node = node.nextSibling) - if (node.nodeType == 1) return node; - return null; - }, - - previousElementSibling: function(node) { - while (node = node.previousSibling) - if (node.nodeType == 1) return node; - return null; - }, - - // TOKEN FUNCTIONS - tagName: function(nodes, root, tagName, combinator) { - var uTagName = tagName.toUpperCase(); - var results = [], h = Selector.handlers; - if (nodes) { - if (combinator) { - // fastlane for ordinary descendant combinators - if (combinator == "descendant") { - for (var i = 0, node; node = nodes[i]; i++) - h.concat(results, node.getElementsByTagName(tagName)); - return results; - } else nodes = this[combinator](nodes); - if (tagName == "*") return nodes; - } - for (var i = 0, node; node = nodes[i]; i++) - if (node.tagName.toUpperCase() === uTagName) results.push(node); - return results; - } else return root.getElementsByTagName(tagName); - }, - - id: function(nodes, root, id, combinator) { - var targetNode = $(id), h = Selector.handlers; - if (!targetNode) return []; - if (!nodes && root == document) return [targetNode]; - if (nodes) { - if (combinator) { - if (combinator == 'child') { - for (var i = 0, node; node = nodes[i]; i++) - if (targetNode.parentNode == node) return [targetNode]; - } else if (combinator == 'descendant') { - for (var i = 0, node; node = nodes[i]; i++) - if (Element.descendantOf(targetNode, node)) return [targetNode]; - } else if (combinator == 'adjacent') { - for (var i = 0, node; node = nodes[i]; i++) - if (Selector.handlers.previousElementSibling(targetNode) == node) - return [targetNode]; - } else nodes = h[combinator](nodes); - } - for (var i = 0, node; node = nodes[i]; i++) - if (node == targetNode) return [targetNode]; - return []; - } - return (targetNode && Element.descendantOf(targetNode, root)) ? [targetNode] : []; - }, - - className: function(nodes, root, className, combinator) { - if (nodes && combinator) nodes = this[combinator](nodes); - return Selector.handlers.byClassName(nodes, root, className); - }, - - byClassName: function(nodes, root, className) { - if (!nodes) nodes = Selector.handlers.descendant([root]); - var needle = ' ' + className + ' '; - for (var i = 0, results = [], node, nodeClassName; node = nodes[i]; i++) { - nodeClassName = node.className; - if (nodeClassName.length == 0) continue; - if (nodeClassName == className || (' ' + nodeClassName + ' ').include(needle)) - results.push(node); - } - return results; - }, - - attrPresence: function(nodes, root, attr, combinator) { - if (!nodes) nodes = root.getElementsByTagName("*"); - if (nodes && combinator) nodes = this[combinator](nodes); - var results = []; - for (var i = 0, node; node = nodes[i]; i++) - if (Element.hasAttribute(node, attr)) results.push(node); - return results; - }, - - attr: function(nodes, root, attr, value, operator, combinator) { - if (!nodes) nodes = root.getElementsByTagName("*"); - if (nodes && combinator) nodes = this[combinator](nodes); - var handler = Selector.operators[operator], results = []; - for (var i = 0, node; node = nodes[i]; i++) { - var nodeValue = Element.readAttribute(node, attr); - if (nodeValue === null) continue; - if (handler(nodeValue, value)) results.push(node); - } - return results; - }, - - pseudo: function(nodes, name, value, root, combinator) { - if (nodes && combinator) nodes = this[combinator](nodes); - if (!nodes) nodes = root.getElementsByTagName("*"); - return Selector.pseudos[name](nodes, value, root); - } - }, - - pseudos: { - 'first-child': function(nodes, value, root) { - for (var i = 0, results = [], node; node = nodes[i]; i++) { - if (Selector.handlers.previousElementSibling(node)) continue; - results.push(node); - } - return results; - }, - 'last-child': function(nodes, value, root) { - for (var i = 0, results = [], node; node = nodes[i]; i++) { - if (Selector.handlers.nextElementSibling(node)) continue; - results.push(node); - } - return results; - }, - 'only-child': function(nodes, value, root) { - var h = Selector.handlers; - for (var i = 0, results = [], node; node = nodes[i]; i++) - if (!h.previousElementSibling(node) && !h.nextElementSibling(node)) - results.push(node); - return results; - }, - 'nth-child': function(nodes, formula, root) { - return Selector.pseudos.nth(nodes, formula, root); - }, - 'nth-last-child': function(nodes, formula, root) { - return Selector.pseudos.nth(nodes, formula, root, true); - }, - 'nth-of-type': function(nodes, formula, root) { - return Selector.pseudos.nth(nodes, formula, root, false, true); - }, - 'nth-last-of-type': function(nodes, formula, root) { - return Selector.pseudos.nth(nodes, formula, root, true, true); - }, - 'first-of-type': function(nodes, formula, root) { - return Selector.pseudos.nth(nodes, "1", root, false, true); - }, - 'last-of-type': function(nodes, formula, root) { - return Selector.pseudos.nth(nodes, "1", root, true, true); - }, - 'only-of-type': function(nodes, formula, root) { - var p = Selector.pseudos; - return p['last-of-type'](p['first-of-type'](nodes, formula, root), formula, root); - }, - - // handles the an+b logic - getIndices: function(a, b, total) { - if (a == 0) return b > 0 ? [b] : []; - return $R(1, total).inject([], function(memo, i) { - if (0 == (i - b) % a && (i - b) / a >= 0) memo.push(i); - return memo; - }); - }, - - // handles nth(-last)-child, nth(-last)-of-type, and (first|last)-of-type - nth: function(nodes, formula, root, reverse, ofType) { - if (nodes.length == 0) return []; - if (formula == 'even') formula = '2n+0'; - if (formula == 'odd') formula = '2n+1'; - var h = Selector.handlers, results = [], indexed = [], m; - h.mark(nodes); - for (var i = 0, node; node = nodes[i]; i++) { - if (!node.parentNode._countedByPrototype) { - h.index(node.parentNode, reverse, ofType); - indexed.push(node.parentNode); - } - } - if (formula.match(/^\d+$/)) { // just a number - formula = Number(formula); - for (var i = 0, node; node = nodes[i]; i++) - if (node.nodeIndex == formula) results.push(node); - } else if (m = formula.match(/^(-?\d*)?n(([+-])(\d+))?/)) { // an+b - if (m[1] == "-") m[1] = -1; - var a = m[1] ? Number(m[1]) : 1; - var b = m[2] ? Number(m[2]) : 0; - var indices = Selector.pseudos.getIndices(a, b, nodes.length); - for (var i = 0, node, l = indices.length; node = nodes[i]; i++) { - for (var j = 0; j < l; j++) - if (node.nodeIndex == indices[j]) results.push(node); - } - } - h.unmark(nodes); - h.unmark(indexed); - return results; - }, - - 'empty': function(nodes, value, root) { - for (var i = 0, results = [], node; node = nodes[i]; i++) { - // IE treats comments as element nodes - if (node.tagName == '!' || (node.firstChild && !node.innerHTML.match(/^\s*$/))) continue; - results.push(node); - } - return results; - }, - - 'not': function(nodes, selector, root) { - var h = Selector.handlers, selectorType, m; - var exclusions = new Selector(selector).findElements(root); - h.mark(exclusions); - for (var i = 0, results = [], node; node = nodes[i]; i++) - if (!node._countedByPrototype) results.push(node); - h.unmark(exclusions); - return results; - }, - - 'enabled': function(nodes, value, root) { - for (var i = 0, results = [], node; node = nodes[i]; i++) - if (!node.disabled) results.push(node); - return results; - }, - - 'disabled': function(nodes, value, root) { - for (var i = 0, results = [], node; node = nodes[i]; i++) - if (node.disabled) results.push(node); - return results; - }, - - 'checked': function(nodes, value, root) { - for (var i = 0, results = [], node; node = nodes[i]; i++) - if (node.checked) results.push(node); - return results; - } - }, - - operators: { - '=': function(nv, v) { return nv == v; }, - '!=': function(nv, v) { return nv != v; }, - '^=': function(nv, v) { return nv.startsWith(v); }, - '$=': function(nv, v) { return nv.endsWith(v); }, - '*=': function(nv, v) { return nv.include(v); }, - '~=': function(nv, v) { return (' ' + nv + ' ').include(' ' + v + ' '); }, - '|=': function(nv, v) { return ('-' + nv.toUpperCase() + '-').include('-' + v.toUpperCase() + '-'); } - }, - - split: function(expression) { - var expressions = []; - expression.scan(/(([\w#:.~>+()\s-]+|\*|\[.*?\])+)\s*(,|$)/, function(m) { - expressions.push(m[1].strip()); - }); - return expressions; - }, - - matchElements: function(elements, expression) { - var matches = $$(expression), h = Selector.handlers; - h.mark(matches); - for (var i = 0, results = [], element; element = elements[i]; i++) - if (element._countedByPrototype) results.push(element); - h.unmark(matches); - return results; - }, - - findElement: function(elements, expression, index) { - if (Object.isNumber(expression)) { - index = expression; expression = false; - } - return Selector.matchElements(elements, expression || '*')[index || 0]; - }, - - findChildElements: function(element, expressions) { - expressions = Selector.split(expressions.join(',')); - var results = [], h = Selector.handlers; - for (var i = 0, l = expressions.length, selector; i < l; i++) { - selector = new Selector(expressions[i].strip()); - h.concat(results, selector.findElements(element)); - } - return (l > 1) ? h.unique(results) : results; - } -}); - -if (Prototype.Browser.IE) { - Object.extend(Selector.handlers, { - // IE returns comment nodes on getElementsByTagName("*"). - // Filter them out. - concat: function(a, b) { - for (var i = 0, node; node = b[i]; i++) - if (node.tagName !== "!") a.push(node); - return a; - }, - - // IE improperly serializes _countedByPrototype in (inner|outer)HTML. - unmark: function(nodes) { - for (var i = 0, node; node = nodes[i]; i++) - node.removeAttribute('_countedByPrototype'); - return nodes; - } - }); -} - -function $$() { - return Selector.findChildElements(document, $A(arguments)); -} -var Form = { - reset: function(form) { - $(form).reset(); - return form; - }, - - serializeElements: function(elements, options) { - if (typeof options != 'object') options = { hash: !!options }; - else if (Object.isUndefined(options.hash)) options.hash = true; - var key, value, submitted = false, submit = options.submit; - - var data = elements.inject({ }, function(result, element) { - if (!element.disabled && element.name) { - key = element.name; value = $(element).getValue(); - if (value != null && (element.type != 'submit' || (!submitted && - submit !== false && (!submit || key == submit) && (submitted = true)))) { - if (key in result) { - // a key is already present; construct an array of values - if (!Object.isArray(result[key])) result[key] = [result[key]]; - result[key].push(value); - } - else result[key] = value; - } - } - return result; - }); - - return options.hash ? data : Object.toQueryString(data); - } -}; - -Form.Methods = { - serialize: function(form, options) { - return Form.serializeElements(Form.getElements(form), options); - }, - - getElements: function(form) { - return $A($(form).getElementsByTagName('*')).inject([], - function(elements, child) { - if (Form.Element.Serializers[child.tagName.toLowerCase()]) - elements.push(Element.extend(child)); - return elements; - } - ); - }, - - getInputs: function(form, typeName, name) { - form = $(form); - var inputs = form.getElementsByTagName('input'); - - if (!typeName && !name) return $A(inputs).map(Element.extend); - - for (var i = 0, matchingInputs = [], length = inputs.length; i < length; i++) { - var input = inputs[i]; - if ((typeName && input.type != typeName) || (name && input.name != name)) - continue; - matchingInputs.push(Element.extend(input)); - } - - return matchingInputs; - }, - - disable: function(form) { - form = $(form); - Form.getElements(form).invoke('disable'); - return form; - }, - - enable: function(form) { - form = $(form); - Form.getElements(form).invoke('enable'); - return form; - }, - - findFirstElement: function(form) { - var elements = $(form).getElements().findAll(function(element) { - return 'hidden' != element.type && !element.disabled; - }); - var firstByIndex = elements.findAll(function(element) { - return element.hasAttribute('tabIndex') && element.tabIndex >= 0; - }).sortBy(function(element) { return element.tabIndex }).first(); - - return firstByIndex ? firstByIndex : elements.find(function(element) { - return ['input', 'select', 'textarea'].include(element.tagName.toLowerCase()); - }); - }, - - focusFirstElement: function(form) { - form = $(form); - form.findFirstElement().activate(); - return form; - }, - - request: function(form, options) { - form = $(form), options = Object.clone(options || { }); - - var params = options.parameters, action = form.readAttribute('action') || ''; - if (action.blank()) action = window.location.href; - options.parameters = form.serialize(true); - - if (params) { - if (Object.isString(params)) params = params.toQueryParams(); - Object.extend(options.parameters, params); - } - - if (form.hasAttribute('method') && !options.method) - options.method = form.method; - - return new Ajax.Request(action, options); - } -}; - -/*--------------------------------------------------------------------------*/ - -Form.Element = { - focus: function(element) { - $(element).focus(); - return element; - }, - - select: function(element) { - $(element).select(); - return element; - } -}; - -Form.Element.Methods = { - serialize: function(element) { - element = $(element); - if (!element.disabled && element.name) { - var value = element.getValue(); - if (value != undefined) { - var pair = { }; - pair[element.name] = value; - return Object.toQueryString(pair); - } - } - return ''; - }, - - getValue: function(element) { - element = $(element); - var method = element.tagName.toLowerCase(); - return Form.Element.Serializers[method](element); - }, - - setValue: function(element, value) { - element = $(element); - var method = element.tagName.toLowerCase(); - Form.Element.Serializers[method](element, value); - return element; - }, - - clear: function(element) { - $(element).value = ''; - return element; - }, - - present: function(element) { - return $(element).value != ''; - }, - - activate: function(element) { - element = $(element); - try { - element.focus(); - if (element.select && (element.tagName.toLowerCase() != 'input' || - !['button', 'reset', 'submit'].include(element.type))) - element.select(); - } catch (e) { } - return element; - }, - - disable: function(element) { - element = $(element); - element.blur(); - element.disabled = true; - return element; - }, - - enable: function(element) { - element = $(element); - element.disabled = false; - return element; - } -}; - -/*--------------------------------------------------------------------------*/ - -var Field = Form.Element; -var $F = Form.Element.Methods.getValue; - -/*--------------------------------------------------------------------------*/ - -Form.Element.Serializers = { - input: function(element, value) { - switch (element.type.toLowerCase()) { - case 'checkbox': - case 'radio': - return Form.Element.Serializers.inputSelector(element, value); - default: - return Form.Element.Serializers.textarea(element, value); - } - }, - - inputSelector: function(element, value) { - if (Object.isUndefined(value)) return element.checked ? element.value : null; - else element.checked = !!value; - }, - - textarea: function(element, value) { - if (Object.isUndefined(value)) return element.value; - else element.value = value; - }, - - select: function(element, index) { - if (Object.isUndefined(index)) - return this[element.type == 'select-one' ? - 'selectOne' : 'selectMany'](element); - else { - var opt, value, single = !Object.isArray(index); - for (var i = 0, length = element.length; i < length; i++) { - opt = element.options[i]; - value = this.optionValue(opt); - if (single) { - if (value == index) { - opt.selected = true; - return; - } - } - else opt.selected = index.include(value); - } - } - }, - - selectOne: function(element) { - var index = element.selectedIndex; - return index >= 0 ? this.optionValue(element.options[index]) : null; - }, - - selectMany: function(element) { - var values, length = element.length; - if (!length) return null; - - for (var i = 0, values = []; i < length; i++) { - var opt = element.options[i]; - if (opt.selected) values.push(this.optionValue(opt)); - } - return values; - }, - - optionValue: function(opt) { - // extend element because hasAttribute may not be native - return Element.extend(opt).hasAttribute('value') ? opt.value : opt.text; - } -}; - -/*--------------------------------------------------------------------------*/ - -Abstract.TimedObserver = Class.create(PeriodicalExecuter, { - initialize: function($super, element, frequency, callback) { - $super(callback, frequency); - this.element = $(element); - this.lastValue = this.getValue(); - }, - - execute: function() { - var value = this.getValue(); - if (Object.isString(this.lastValue) && Object.isString(value) ? - this.lastValue != value : String(this.lastValue) != String(value)) { - this.callback(this.element, value); - this.lastValue = value; - } - } -}); - -Form.Element.Observer = Class.create(Abstract.TimedObserver, { - getValue: function() { - return Form.Element.getValue(this.element); - } -}); - -Form.Observer = Class.create(Abstract.TimedObserver, { - getValue: function() { - return Form.serialize(this.element); - } -}); - -/*--------------------------------------------------------------------------*/ - -Abstract.EventObserver = Class.create({ - initialize: function(element, callback) { - this.element = $(element); - this.callback = callback; - - this.lastValue = this.getValue(); - if (this.element.tagName.toLowerCase() == 'form') - this.registerFormCallbacks(); - else - this.registerCallback(this.element); - }, - - onElementEvent: function() { - var value = this.getValue(); - if (this.lastValue != value) { - this.callback(this.element, value); - this.lastValue = value; - } - }, - - registerFormCallbacks: function() { - Form.getElements(this.element).each(this.registerCallback, this); - }, - - registerCallback: function(element) { - if (element.type) { - switch (element.type.toLowerCase()) { - case 'checkbox': - case 'radio': - Event.observe(element, 'click', this.onElementEvent.bind(this)); - break; - default: - Event.observe(element, 'change', this.onElementEvent.bind(this)); - break; - } - } - } -}); - -Form.Element.EventObserver = Class.create(Abstract.EventObserver, { - getValue: function() { - return Form.Element.getValue(this.element); - } -}); - -Form.EventObserver = Class.create(Abstract.EventObserver, { - getValue: function() { - return Form.serialize(this.element); - } -}); -if (!window.Event) var Event = { }; - -Object.extend(Event, { - KEY_BACKSPACE: 8, - KEY_TAB: 9, - KEY_RETURN: 13, - KEY_ESC: 27, - KEY_LEFT: 37, - KEY_UP: 38, - KEY_RIGHT: 39, - KEY_DOWN: 40, - KEY_DELETE: 46, - KEY_HOME: 36, - KEY_END: 35, - KEY_PAGEUP: 33, - KEY_PAGEDOWN: 34, - KEY_INSERT: 45, - - cache: { }, - - relatedTarget: function(event) { - var element; - switch(event.type) { - case 'mouseover': element = event.fromElement; break; - case 'mouseout': element = event.toElement; break; - default: return null; - } - return Element.extend(element); - } -}); - -Event.Methods = (function() { - var isButton; - - if (Prototype.Browser.IE) { - var buttonMap = { 0: 1, 1: 4, 2: 2 }; - isButton = function(event, code) { - return event.button == buttonMap[code]; - }; - - } else if (Prototype.Browser.WebKit) { - isButton = function(event, code) { - switch (code) { - case 0: return event.which == 1 && !event.metaKey; - case 1: return event.which == 1 && event.metaKey; - default: return false; - } - }; - - } else { - isButton = function(event, code) { - return event.which ? (event.which === code + 1) : (event.button === code); - }; - } - - return { - isLeftClick: function(event) { return isButton(event, 0) }, - isMiddleClick: function(event) { return isButton(event, 1) }, - isRightClick: function(event) { return isButton(event, 2) }, - - element: function(event) { - var node = Event.extend(event).target; - return Element.extend(node.nodeType == Node.TEXT_NODE ? node.parentNode : node); - }, - - findElement: function(event, expression) { - var element = Event.element(event); - if (!expression) return element; - var elements = [element].concat(element.ancestors()); - return Selector.findElement(elements, expression, 0); - }, - - pointer: function(event) { - var docElement = document.documentElement, body = document.body; - return { - x: event.pageX || (event.clientX + - (docElement.scrollLeft || body.scrollLeft) - - (docElement.clientLeft || 0)), - y: event.pageY || (event.clientY + - (docElement.scrollTop || body.scrollTop) - - (docElement.clientTop || 0)) - }; - }, - - pointerX: function(event) { return Event.pointer(event).x }, - pointerY: function(event) { return Event.pointer(event).y }, - - stop: function(event) { - Event.extend(event); - event.preventDefault(); - event.stopPropagation(); - event.stopped = true; - } - }; -})(); - -Event.extend = (function() { - var methods = Object.keys(Event.Methods).inject({ }, function(m, name) { - m[name] = Event.Methods[name].methodize(); - return m; - }); - - if (Prototype.Browser.IE) { - Object.extend(methods, { - stopPropagation: function() { this.cancelBubble = true }, - preventDefault: function() { this.returnValue = false }, - inspect: function() { return "[object Event]" } - }); - - return function(event) { - if (!event) return false; - if (event._extendedByPrototype) return event; - - event._extendedByPrototype = Prototype.emptyFunction; - var pointer = Event.pointer(event); - Object.extend(event, { - target: event.srcElement, - relatedTarget: Event.relatedTarget(event), - pageX: pointer.x, - pageY: pointer.y - }); - return Object.extend(event, methods); - }; - - } else { - Event.prototype = Event.prototype || document.createEvent("HTMLEvents").__proto__; - Object.extend(Event.prototype, methods); - return Prototype.K; - } -})(); - -Object.extend(Event, (function() { - var cache = Event.cache; - - function getEventID(element) { - if (element._prototypeEventID) return element._prototypeEventID[0]; - arguments.callee.id = arguments.callee.id || 1; - return element._prototypeEventID = [++arguments.callee.id]; - } - - function getDOMEventName(eventName) { - if (eventName && eventName.include(':')) return "dataavailable"; - return eventName; - } - - function getCacheForID(id) { - return cache[id] = cache[id] || { }; - } - - function getWrappersForEventName(id, eventName) { - var c = getCacheForID(id); - return c[eventName] = c[eventName] || []; - } - - function createWrapper(element, eventName, handler) { - var id = getEventID(element); - var c = getWrappersForEventName(id, eventName); - if (c.pluck("handler").include(handler)) return false; - - var wrapper = function(event) { - if (!Event || !Event.extend || - (event.eventName && event.eventName != eventName)) - return false; - - Event.extend(event); - handler.call(element, event); - }; - - wrapper.handler = handler; - c.push(wrapper); - return wrapper; - } - - function findWrapper(id, eventName, handler) { - var c = getWrappersForEventName(id, eventName); - return c.find(function(wrapper) { return wrapper.handler == handler }); - } - - function destroyWrapper(id, eventName, handler) { - var c = getCacheForID(id); - if (!c[eventName]) return false; - c[eventName] = c[eventName].without(findWrapper(id, eventName, handler)); - } - - function destroyCache() { - for (var id in cache) - for (var eventName in cache[id]) - cache[id][eventName] = null; - } - - if (window.attachEvent) { - window.attachEvent("onunload", destroyCache); - } - - return { - observe: function(element, eventName, handler) { - element = $(element); - var name = getDOMEventName(eventName); - - var wrapper = createWrapper(element, eventName, handler); - if (!wrapper) return element; - - if (element.addEventListener) { - element.addEventListener(name, wrapper, false); - } else { - element.attachEvent("on" + name, wrapper); - } - - return element; - }, - - stopObserving: function(element, eventName, handler) { - element = $(element); - var id = getEventID(element), name = getDOMEventName(eventName); - - if (!handler && eventName) { - getWrappersForEventName(id, eventName).each(function(wrapper) { - element.stopObserving(eventName, wrapper.handler); - }); - return element; - - } else if (!eventName) { - Object.keys(getCacheForID(id)).each(function(eventName) { - element.stopObserving(eventName); - }); - return element; - } - - var wrapper = findWrapper(id, eventName, handler); - if (!wrapper) return element; - - if (element.removeEventListener) { - element.removeEventListener(name, wrapper, false); - } else { - element.detachEvent("on" + name, wrapper); - } - - destroyWrapper(id, eventName, handler); - - return element; - }, - - fire: function(element, eventName, memo) { - element = $(element); - if (element == document && document.createEvent && !element.dispatchEvent) - element = document.documentElement; - - var event; - if (document.createEvent) { - event = document.createEvent("HTMLEvents"); - event.initEvent("dataavailable", true, true); - } else { - event = document.createEventObject(); - event.eventType = "ondataavailable"; - } - - event.eventName = eventName; - event.memo = memo || { }; - - if (document.createEvent) { - element.dispatchEvent(event); - } else { - element.fireEvent(event.eventType, event); - } - - return Event.extend(event); - } - }; -})()); - -Object.extend(Event, Event.Methods); - -Element.addMethods({ - fire: Event.fire, - observe: Event.observe, - stopObserving: Event.stopObserving -}); - -Object.extend(document, { - fire: Element.Methods.fire.methodize(), - observe: Element.Methods.observe.methodize(), - stopObserving: Element.Methods.stopObserving.methodize(), - loaded: false -}); - -(function() { - /* Support for the DOMContentLoaded event is based on work by Dan Webb, - Matthias Miller, Dean Edwards and John Resig. */ - - var timer; - - function fireContentLoadedEvent() { - if (document.loaded) return; - if (timer) window.clearInterval(timer); - document.fire("dom:loaded"); - document.loaded = true; - } - - if (document.addEventListener) { - if (Prototype.Browser.WebKit) { - timer = window.setInterval(function() { - if (/loaded|complete/.test(document.readyState)) - fireContentLoadedEvent(); - }, 0); - - Event.observe(window, "load", fireContentLoadedEvent); - - } else { - document.addEventListener("DOMContentLoaded", - fireContentLoadedEvent, false); - } - - } else { - document.write("