diff --git a/application/config/locale.php b/application/config/locale.php index 87ac931ee0..b692c00aae 100644 --- a/application/config/locale.php +++ b/application/config/locale.php @@ -19,4 +19,11 @@ * Locale timezone. Defaults to use the server timezone. * @see http://php.net/timezones */ -$config['timezone'] = ''; \ No newline at end of file +$config['timezone'] = ''; + +/** + * Force text-direction to be either LTR or RTL + * Possible values: 'rtl' 'ltr' or FALSE + * @see Ush_Locale::is_rtl_language() + */ +$config['force_text_direction'] = FALSE; diff --git a/application/config/requirements.php b/application/config/requirements.php new file mode 100644 index 0000000000..33798c5b07 --- /dev/null +++ b/application/config/requirements.php @@ -0,0 +1,41 @@ + tag instead of the
tag. + * This means script downloads won't block other HTTP-requests, + * which can be a performance improvement. + * @see Requirements_Backend::$write_js_to_body for details + **/ +$config['write_js_to_body'] = FALSE; \ No newline at end of file diff --git a/application/controllers/admin.php b/application/controllers/admin.php index 9484a9dd96..e8e7ad8caa 100644 --- a/application/controllers/admin.php +++ b/application/controllers/admin.php @@ -90,6 +90,7 @@ public function __construct() // Themes Helper $this->themes = new Themes(); + $this->themes->admin = TRUE; // Admin is not logged in, or this is a member (not admin) if ( ! $this->auth->logged_in('login')) @@ -118,24 +119,26 @@ public function __construct() // Retrieve Default Settings $this->template->site_name = Kohana::config('settings.site_name'); $this->template->mapstraction = Kohana::config('settings.mapstraction'); - $this->template->api_url = Kohana::config('settings.api_url'); + $this->themes->api_url = Kohana::config('settings.api_url'); // Javascript Header - $this->template->map_enabled = FALSE; - $this->template->datepicker_enabled = FALSE; - $this->template->flot_enabled = FALSE; - $this->template->treeview_enabled = FALSE; - $this->template->protochart_enabled = FALSE; - $this->template->colorpicker_enabled = FALSE; - $this->template->editor_enabled = FALSE; - $this->template->tablerowsort_enabled = FALSE; - $this->template->json2_enabled = FALSE; - $this->template->js = ''; + $this->themes->map_enabled = FALSE; + $this->themes->datepicker_enabled = FALSE; + $this->themes->flot_enabled = FALSE; + $this->themes->treeview_enabled = FALSE; + $this->themes->protochart_enabled = FALSE; + $this->themes->colorpicker_enabled = FALSE; + $this->themes->editor_enabled = FALSE; + $this->themes->tablerowsort_enabled = FALSE; + $this->themes->json2_enabled = FALSE; + $this->themes->hovertip_enabled = TRUE; + $this->themes->slider_enabled = TRUE; + $this->themes->js = ''; $this->template->form_error = FALSE; // Initialize some variables for raphael impact charts - $this->template->raphael_enabled = FALSE; - $this->template->impact_json = ''; + $this->themes->raphael_enabled = FALSE; + $this->themes->impact_json = ''; // Generate main tab navigation list. $this->template->main_tabs = admin::main_tabs(); @@ -152,12 +155,10 @@ public function __construct() $this->template->header_nav->loggedin_role = $this->user->dashboard(); $this->template->header_nav->site_name = Kohana::config('settings.site_name'); - // Header and Footer Blocks - $this->template->header_block = $this->themes->admin_header_block(); - $this->template->footer_block = $this->themes->footer_block(); - // Language switcher $this->template->languages = $this->themes->languages(); + + Event::add('ushahidi_filter.view_pre_render.admin_layout', array($this, '_pre_render')); } public function index() @@ -220,6 +221,18 @@ private function _new_or_not($release_version=NULL, $version_ushahidi=NULL) return TRUE; } + + /** + * Trigger themes->admin_requirements() at the last minute + * + * This is in case features are enabled/disabled + */ + public function _pre_render() + { + $this->themes->requirements(); + $this->template->header_block = $this->themes->header_block(); + $this->template->footer_block = $this->themes->footer_block(); + } } // End Admin diff --git a/application/controllers/admin/addons/plugins.php b/application/controllers/admin/addons/plugins.php index 0080a44817..ee5e5518b4 100644 --- a/application/controllers/admin/addons/plugins.php +++ b/application/controllers/admin/addons/plugins.php @@ -198,7 +198,7 @@ public function index() $this->template->content->status = $status; // Javascript Header - $this->template->js = new View('admin/addons/addons_js'); + $this->themes->js = new View('admin/addons/addons_js'); } } diff --git a/application/controllers/admin/checkins.php b/application/controllers/admin/checkins.php index 0745c5202b..14488fca89 100644 --- a/application/controllers/admin/checkins.php +++ b/application/controllers/admin/checkins.php @@ -111,7 +111,7 @@ function index() $this->template->content->total_items = $pagination->total_items; // Javascript Header - $this->template->js = new View('admin/checkins/checkins_js'); + $this->themes->js = new View('admin/checkins/checkins_js'); } } diff --git a/application/controllers/admin/comments.php b/application/controllers/admin/comments.php index 308e67dd1c..6e760aaf31 100644 --- a/application/controllers/admin/comments.php +++ b/application/controllers/admin/comments.php @@ -186,7 +186,7 @@ function index($page = 1) $this->template->content->status = $status; // Javascript Header - $this->template->js = new View('admin/comments/comments_js'); + $this->themes->js = new View('admin/comments/comments_js'); } } diff --git a/application/controllers/admin/dashboard.php b/application/controllers/admin/dashboard.php index bd8cecbe51..dcda5cc2eb 100644 --- a/application/controllers/admin/dashboard.php +++ b/application/controllers/admin/dashboard.php @@ -96,8 +96,8 @@ public function index() ->find_all(); // Javascript Header - $this->template->protochart_enabled = TRUE; - $this->template->js = new View('admin/stats/stats_js'); + $this->themes->protochart_enabled = TRUE; + $this->themes->js = new View('admin/stats/stats_js'); $this->template->content->failure = ''; diff --git a/application/controllers/admin/manage.php b/application/controllers/admin/manage.php index d8261d0a97..028374389c 100644 --- a/application/controllers/admin/manage.php +++ b/application/controllers/admin/manage.php @@ -351,13 +351,13 @@ public function index() $this->template->content->parents_array = $parents_array; // Javascript Header - $this->template->colorpicker_enabled = TRUE; - $this->template->tablerowsort_enabled = TRUE; - $this->template->js = new View('admin/manage/categories/categories_js'); + $this->themes->colorpicker_enabled = TRUE; + $this->themes->tablerowsort_enabled = TRUE; + $this->themes->js = new View('admin/manage/categories/categories_js'); $this->template->form_error = $form_error; $this->template->content->locale_array = $locales; - $this->template->js->locale_array = $locales; + $this->themes->js->locale_array = $locales; } /** @@ -530,8 +530,8 @@ public function pages() $this->template->content->errors = $errors; // Javascript Header - $this->template->editor_enabled = TRUE; - $this->template->js = new View('admin/manage/pages/pages_js'); + $this->themes->editor_enabled = TRUE; + $this->themes->js = new View('admin/manage/pages/pages_js'); } @@ -634,8 +634,8 @@ public function feeds() $this->template->content->errors = $errors; // Javascript Header - $this->template->colorpicker_enabled = TRUE; - $this->template->js = new View('admin/manage/feeds/feeds_js'); + $this->themes->colorpicker_enabled = TRUE; + $this->themes->js = new View('admin/manage/feeds/feeds_js'); } /** @@ -702,7 +702,7 @@ public function feeds_items() $this->template->content->total_items = $pagination->total_items; // Javascript Header - $this->template->js = new View('admin/manage/feeds/items_js'); + $this->themes->js = new View('admin/manage/feeds/items_js'); } /** @@ -913,8 +913,8 @@ public function layers() $this->template->content->layers = $layers; // Javascript Header - $this->template->colorpicker_enabled = TRUE; - $this->template->js = new View('admin/manage/layers/layers_js'); + $this->themes->colorpicker_enabled = TRUE; + $this->themes->js = new View('admin/manage/layers/layers_js'); } /** diff --git a/application/controllers/admin/manage/actions.php b/application/controllers/admin/manage/actions.php index e47734c2c9..7a755580d5 100644 --- a/application/controllers/admin/manage/actions.php +++ b/application/controllers/admin/manage/actions.php @@ -34,18 +34,18 @@ function index() $this->template->content = new View('admin/manage/actions/main'); $this->template->content->title = Kohana::lang('ui_admin.actions'); - $this->template->map_enabled = TRUE; - $this->template->treeview_enabled = TRUE; + $this->themes->map_enabled = TRUE; + $this->themes->treeview_enabled = TRUE; - $this->template->js = new View('admin/manage/actions/actions_js'); - $this->template->js->default_map = Kohana::config('settings.default_map'); - $this->template->js->default_zoom = Kohana::config('settings.default_zoom'); - $this->template->js->latitude = Kohana::config('settings.default_lat'); - $this->template->js->longitude = Kohana::config('settings.default_lon'); + $this->themes->js = new View('admin/manage/actions/actions_js'); + $this->themes->js->default_map = Kohana::config('settings.default_map'); + $this->themes->js->default_zoom = Kohana::config('settings.default_zoom'); + $this->themes->js->latitude = Kohana::config('settings.default_lat'); + $this->themes->js->longitude = Kohana::config('settings.default_lon'); // TODO: Figure out what to do with this - $this->template->js->incident_zoom = array(); - $this->template->js->geometries = array(); + $this->themes->js->incident_zoom = array(); + $this->themes->js->geometries = array(); $trigger_options = $this->_trigger_options(); $response_options = $this->_response_options(); @@ -265,7 +265,7 @@ function index() $this->template->content->errors = $errors; // Enable date picker - $this->template->datepicker_enabled = TRUE; + $this->themes->datepicker_enabled = TRUE; } function changestate(){ diff --git a/application/controllers/admin/manage/alerts.php b/application/controllers/admin/manage/alerts.php index ce2cb45a8d..ab8dea4221 100644 --- a/application/controllers/admin/manage/alerts.php +++ b/application/controllers/admin/manage/alerts.php @@ -161,6 +161,6 @@ public function index() $this->template->content->keyword = $keyword; // Javascript Header - $this->template->js = new View('admin/manage/alerts/alerts_js'); + $this->themes->js = new View('admin/manage/alerts/alerts_js'); } } \ No newline at end of file diff --git a/application/controllers/admin/manage/badges.php b/application/controllers/admin/manage/badges.php index 23a162b410..79b6ebc040 100644 --- a/application/controllers/admin/manage/badges.php +++ b/application/controllers/admin/manage/badges.php @@ -226,6 +226,6 @@ function index() $this->template->content->users = $users; // Javascript Header - $this->template->js = new View('admin/manage/badges/badges_js'); + $this->themes->js = new View('admin/manage/badges/badges_js'); } } diff --git a/application/controllers/admin/manage/blocks.php b/application/controllers/admin/manage/blocks.php index 73ac5208e2..5724b9892a 100644 --- a/application/controllers/admin/manage/blocks.php +++ b/application/controllers/admin/manage/blocks.php @@ -111,8 +111,8 @@ function index() $this->template->content->sorted_blocks = $sorted_blocks; // Javascript Header - $this->template->tablerowsort_enabled = TRUE; - $this->template->js = new View('admin/manage/blocks/blocks_js'); + $this->themes->tablerowsort_enabled = TRUE; + $this->themes->js = new View('admin/manage/blocks/blocks_js'); } public function sort() diff --git a/application/controllers/admin/manage/forms.php b/application/controllers/admin/manage/forms.php index 3abeda4635..7650a276b0 100755 --- a/application/controllers/admin/manage/forms.php +++ b/application/controllers/admin/manage/forms.php @@ -173,8 +173,8 @@ public function index() $this->template->content->errors = $errors; // Javascript Header - $this->template->js = new View('admin/manage/forms/forms_js'); - $this->template->js->form_id = $form_id; + $this->themes->js = new View('admin/manage/forms/forms_js'); + $this->themes->js->form_id = $form_id; $this->template->form_error = $form_error; } diff --git a/application/controllers/admin/manage/scheduler.php b/application/controllers/admin/manage/scheduler.php index 98db64b0cd..cc437f9802 100644 --- a/application/controllers/admin/manage/scheduler.php +++ b/application/controllers/admin/manage/scheduler.php @@ -197,7 +197,7 @@ function index() $this->template->content->errors = $errors; // Javascript Header - $this->template->js = new View('admin/manage/scheduler/scheduler_js'); + $this->themes->js = new View('admin/manage/scheduler/scheduler_js'); } diff --git a/application/controllers/admin/messages.php b/application/controllers/admin/messages.php index 9c770e97ef..4280331857 100755 --- a/application/controllers/admin/messages.php +++ b/application/controllers/admin/messages.php @@ -245,7 +245,7 @@ public function index($service_id = 1) $this->template->content->level = $level; // Javascript Header - $this->template->js = new View('admin/messages/messages_js'); + $this->themes->js = new View('admin/messages/messages_js'); } /** diff --git a/application/controllers/admin/messages/reporters.php b/application/controllers/admin/messages/reporters.php index 146d1f095c..81a3ef48fc 100644 --- a/application/controllers/admin/messages/reporters.php +++ b/application/controllers/admin/messages/reporters.php @@ -216,12 +216,12 @@ public function index($service_id = 1) $this->template->content->service_array = Service_Model::get_array(); // Javascript Header - $this->template->map_enabled = TRUE; - $this->template->js = new View('admin/reporters/reporters_js'); - $this->template->js->default_map = Kohana::config('settings.default_map'); - $this->template->js->default_zoom = Kohana::config('settings.default_zoom'); - $this->template->js->latitude = Kohana::config('settings.default_lat'); - $this->template->js->longitude = Kohana::config('settings.default_lon'); - $this->template->js->form_error = $form_error; + $this->themes->map_enabled = TRUE; + $this->themes->js = new View('admin/reporters/reporters_js'); + $this->themes->js->default_map = Kohana::config('settings.default_map'); + $this->themes->js->default_zoom = Kohana::config('settings.default_zoom'); + $this->themes->js->latitude = Kohana::config('settings.default_lat'); + $this->themes->js->longitude = Kohana::config('settings.default_lon'); + $this->themes->js->form_error = $form_error; } } diff --git a/application/controllers/admin/reports.php b/application/controllers/admin/reports.php index 30f74883c3..f382db5b3a 100755 --- a/application/controllers/admin/reports.php +++ b/application/controllers/admin/reports.php @@ -300,12 +300,12 @@ public function index($page = 1) $this->template->content->order_field = $order_field; $this->template->content->sort = $sort; - $this->template->map_enabled = TRUE; - $this->template->json2_enabled = TRUE; - $this->template->treeview_enabled = TRUE; + $this->themes->map_enabled = TRUE; + $this->themes->json2_enabled = TRUE; + $this->themes->treeview_enabled = TRUE; // Javascript Header - $this->template->js = new View('admin/reports/reports_js'); + $this->themes->js = new View('admin/reports/reports_js'); } /** @@ -804,29 +804,29 @@ public function edit($id = FALSE, $saved = FALSE) $this->template->content->next_url = $next_url; // Javascript Header - $this->template->map_enabled = TRUE; - $this->template->colorpicker_enabled = TRUE; - $this->template->treeview_enabled = TRUE; - $this->template->json2_enabled = TRUE; + $this->themes->map_enabled = TRUE; + $this->themes->colorpicker_enabled = TRUE; + $this->themes->treeview_enabled = TRUE; + $this->themes->json2_enabled = TRUE; - $this->template->js = new View('reports/submit_edit_js'); - $this->template->js->edit_mode = TRUE; - $this->template->js->default_map = Kohana::config('settings.default_map'); - $this->template->js->default_zoom = Kohana::config('settings.default_zoom'); + $this->themes->js = new View('reports/submit_edit_js'); + $this->themes->js->edit_mode = TRUE; + $this->themes->js->default_map = Kohana::config('settings.default_map'); + $this->themes->js->default_zoom = Kohana::config('settings.default_zoom'); if ( ! $form['latitude'] OR !$form['latitude']) { - $this->template->js->latitude = Kohana::config('settings.default_lat'); - $this->template->js->longitude = Kohana::config('settings.default_lon'); + $this->themes->js->latitude = Kohana::config('settings.default_lat'); + $this->themes->js->longitude = Kohana::config('settings.default_lon'); } else { - $this->template->js->latitude = $form['latitude']; - $this->template->js->longitude = $form['longitude']; + $this->themes->js->latitude = $form['latitude']; + $this->themes->js->longitude = $form['longitude']; } - $this->template->js->incident_zoom = $form['incident_zoom']; - $this->template->js->geometries = $form['geometry']; + $this->themes->js->incident_zoom = $form['incident_zoom']; + $this->themes->js->geometries = $form['geometry']; // Inline Javascript $this->template->content->date_picker_js = $this->_date_picker_js(); @@ -834,8 +834,8 @@ public function edit($id = FALSE, $saved = FALSE) $this->template->content->new_category_toggle_js = $this->_new_category_toggle_js(); // Pack Javascript - $myPacker = new javascriptpacker($this->template->js , 'Normal', FALSE, FALSE); - $this->template->js = $myPacker->pack(); + $myPacker = new javascriptpacker($this->themes->js , 'Normal', FALSE, FALSE); + $this->themes->js = $myPacker->pack(); } @@ -862,7 +862,7 @@ public function download() 'to_date' => '', 'form_auth_token'=> '' ); - + // Default to all selected $form['data_active'] = array(0,1); $form['data_verified'] = array(0,1); @@ -963,31 +963,31 @@ public function download() // Retrieve reports $incidents = ORM::factory('incident')->where($filter)->orderby('incident_dateadd', 'desc')->find_all(); - + // Retrieve categories $categories = Category_Model::get_categories(FALSE, FALSE, FALSE); - + // Retrieve Forms $forms = ORM::Factory('form')->find_all(); - + // Retrieve Custom forms $custom_forms = customforms::get_custom_form_fields(); // If CSV format is selected if($post->format == 'csv') - { + { $report_csv = download::download_csv($post, $incidents, $custom_forms); + + // Output to browser + header("Content-type: text/x-csv"); + header("Cache-Control: must-revalidate, post-check=0, pre-check=0"); + header("Content-Disposition: attachment; filename=" . time() . ".csv"); + header("Content-Length: " . strlen($report_csv)); + echo $report_csv; + exit; - // Output to browser - header("Content-type: text/x-csv"); - header("Cache-Control: must-revalidate, post-check=0, pre-check=0"); - header("Content-Disposition: attachment; filename=" . time() . ".csv"); - header("Content-Length: " . strlen($report_csv)); - echo $report_csv; - exit; - - } - + } + // If XML format is selected if($post->format == 'xml') { @@ -1017,8 +1017,8 @@ public function download() $this->template->content->form_error = $form_error; // Javascript Header - $this->template->js = new View('admin/reports/download_js'); - $this->template->js->calendar_img = url::base() . "media/img/icon-calendar.gif"; + $this->themes->js = new View('admin/reports/download_js'); + $this->themes->js->calendar_img = url::base() . "media/img/icon-calendar.gif"; } public function upload() @@ -1051,14 +1051,14 @@ public function upload() ->add_rules('uploadfile', 'upload::valid', 'upload::required', 'upload::type[xml,csv]', 'upload::size[3M]'); if($post->validate(TRUE)) - { + { // Establish if file to be uploaded is .xml or .csv format $fileinfo = pathinfo($post['uploadfile']['name']); $extension = $fileinfo['extension']; $allowable_extensions = array ('csv', 'xml'); - + if (file_exists($_FILES['uploadfile']['tmp_name'])) - { + { // If file type uploaded is CSV or XML if (in_array($extension, $allowable_extensions)) { @@ -1076,7 +1076,7 @@ public function upload() else { $errors = $importer->errors; - } + } } else @@ -1097,11 +1097,11 @@ public function upload() foreach($post->errors('reports') as $error) { $errors[] = $error; - } - + } + } - if ( count($errors)) + if (count($errors)) { $this->template->content = new View('admin/reports/upload'); $this->template->content->title = Kohana::lang('ui_admin.upload_reports'); diff --git a/application/controllers/admin/settings.php b/application/controllers/admin/settings.php index 4d4aa1b76a..b1fd48fb37 100755 --- a/application/controllers/admin/settings.php +++ b/application/controllers/admin/settings.php @@ -41,7 +41,7 @@ public function site() { $this->template->content = new View('admin/settings/site'); $this->template->content->title = Kohana::lang('ui_admin.settings'); - $this->template->js = new View('admin/settings/site_js'); + $this->themes->js = new View('admin/settings/site_js'); // setup and initialize form field names $form = array( @@ -290,8 +290,8 @@ public function site() $this->template->content->banner_t = NULL; } - - $this->template->colorpicker_enabled = TRUE; + $this->themes->colorpicker_enabled = TRUE; + $this->themes->slider_enabled = TRUE; $this->template->content->form = $form; $this->template->content->errors = $errors; $this->template->content->form_error = $form_error; @@ -341,7 +341,7 @@ public function site() public function index($saved = false) { // Display all maps - $this->template->api_url = Kohana::config('settings.api_url_all'); + $this->themes->api_url = Kohana::config('settings.api_url_all'); // Current Default Country $current_country = Kohana::config('settings.default_country'); @@ -590,14 +590,14 @@ public function index($saved = false) '0'=>utf8::strtoupper(Kohana::lang('ui_main.no'))); // Javascript Header - $this->template->map_enabled = TRUE; - $this->template->colorpicker_enabled = TRUE; - $this->template->js = new View('admin/settings/settings_js'); - $this->template->js->default_map = $form['default_map']; - $this->template->js->default_zoom = $form['default_zoom']; - $this->template->js->default_lat = $form['default_lat']; - $this->template->js->default_lon = $form['default_lon']; - $this->template->js->all_maps_json = $this->_generate_settings_map_js(); + $this->themes->map_enabled = TRUE; + $this->themes->colorpicker_enabled = TRUE; + $this->themes->js = new View('admin/settings/settings_js'); + $this->themes->js->default_map = $form['default_map']; + $this->themes->js->default_zoom = $form['default_zoom']; + $this->themes->js->default_lat = $form['default_lat']; + $this->themes->js->default_lon = $form['default_lon']; + $this->themes->js->all_maps_json = $this->_generate_settings_map_js(); } @@ -787,7 +787,7 @@ public function email() $this->template->content->email_ssl_array = array('1'=>Kohana::lang('ui_admin.yes'),'0'=>Kohana::lang('ui_admin.no')); // Javascript Header - $this->template->js = new View('admin/settings/email_js'); + $this->themes->js = new View('admin/settings/email_js'); } /** @@ -878,7 +878,7 @@ public function cleanurl() { $this->template->content->form_error = $form_error; $this->template->content->form_saved = $form_saved; $this->template->content->yesno_array = array('1'=>utf8::strtoupper(Kohana::lang('ui_main.yes')),'0'=>utf8::strtoupper(Kohana::lang('ui_main.no'))); - $this->template->content->is_clean_url_enabled = $this->_check_for_clean_url(); + $this->themes->content->is_clean_url_enabled = $this->_check_for_clean_url(); } diff --git a/application/controllers/admin/settings/api.php b/application/controllers/admin/settings/api.php index 98a448f13d..e089742139 100644 --- a/application/controllers/admin/settings/api.php +++ b/application/controllers/admin/settings/api.php @@ -149,7 +149,7 @@ public function index() ); // Javascript header - $this->template->js = new View('admin/settings/api/api_js'); + $this->themes->js = new View('admin/settings/api/api_js'); } /** @@ -267,7 +267,7 @@ public function log() $this->template->content->pagination = $pagination; // Javascript header - $this->template->js = new View('admin/settings/api/logs_js'); + $this->themes->js = new View('admin/settings/api/logs_js'); } /** @@ -349,6 +349,6 @@ public function banned() $this->template->content->pagination = $pagination; // Javascript header - $this->template->js = new View('admin/settings/api/banned_js'); + $this->themes->js = new View('admin/settings/api/banned_js'); } } diff --git a/application/controllers/admin/settings/externalapps.php b/application/controllers/admin/settings/externalapps.php index 2e33ea1986..d8fd31560f 100644 --- a/application/controllers/admin/settings/externalapps.php +++ b/application/controllers/admin/settings/externalapps.php @@ -99,7 +99,7 @@ function index() $this->template->content->form_saved = $form_saved; // Javascript Header - $this->template->js = new View('admin/settings/externalapps/externalapps_js'); + $this->themes->js = new View('admin/settings/externalapps/externalapps_js'); } } diff --git a/application/controllers/admin/stats.php b/application/controllers/admin/stats.php index f5606c74fb..8f2938d0e1 100644 --- a/application/controllers/admin/stats.php +++ b/application/controllers/admin/stats.php @@ -55,8 +55,8 @@ public function reports() $this->template->content->title = Kohana::lang('ui_admin.statistics'); // Javascript Header - $this->template->protochart_enabled = TRUE; - $this->template->js = new View('admin/stats/stats_js'); + $this->themes->protochart_enabled = TRUE; + $this->themes->js = new View('admin/stats/stats_js'); $this->template->content->failure = ''; @@ -192,8 +192,8 @@ public function impact() $this->template->content->title = Kohana::lang('ui_admin.statistics'); // Javascript Header - $this->template->raphael_enabled = TRUE; - $this->template->js = new View('admin/stats/stats_js'); + $this->themes->raphael_enabled = TRUE; + $this->themes->js = new View('admin/stats/stats_js'); $this->template->content->failure = ''; @@ -298,8 +298,8 @@ public function hits() $this->template->content->title = Kohana::lang('ui_admin.statistics'); // Javascript Header - $this->template->protochart_enabled = TRUE; - $this->template->js = new View('admin/stats/stats_js'); + $this->themes->protochart_enabled = TRUE; + $this->themes->js = new View('admin/stats/stats_js'); $this->template->content->failure = ''; @@ -372,7 +372,7 @@ function country() $this->template->content->title = Kohana::lang('ui_admin.statistics'); // Javascript Header - $this->template->js = new View('admin/stats/stats_js'); + $this->themes->js = new View('admin/stats/stats_js'); $this->template->content->failure = ''; diff --git a/application/controllers/admin/upgrade.php b/application/controllers/admin/upgrade.php index deffd3ce23..9b6673a9e1 100644 --- a/application/controllers/admin/upgrade.php +++ b/application/controllers/admin/upgrade.php @@ -76,8 +76,8 @@ public function index() { $this->upgrade->logger("STARTED UPGRADE\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"); $this->template->content = new View('admin/upgrade/upgrade_status'); - $this->template->js = new View('admin/upgrade/upgrade_status_js'); - $this->template->js->backup = $post->chk_db_backup_box; + $this->themes->js = new View('admin/upgrade/upgrade_status_js'); + $this->themes->js->backup = $post->chk_db_backup_box; $this->template->content->title = Kohana::lang('ui_admin.upgrade_ushahidi_status'); $this->session->set('ftp_server', $post->ftp_server); @@ -88,12 +88,12 @@ public function index() Settings_Model::save_setting('ftp_user_name', $post->ftp_user_name); // Log file location - $this->template->js->log_file = url::site(). "admin/upgrade/logfile?f=".$this->session->get('upgrade_session').".txt"; + $this->themes->js->log_file = url::site(). "admin/upgrade/logfile?f=".$this->session->get('upgrade_session').".txt"; } // No! We have validation errors, we need to show the form again, with the errors else { - $this->template->js = new View('admin/upgrade/upgrade_js'); + $this->themes->js = new View('admin/upgrade/upgrade_js'); // repopulate the form fields $form = arr::overwrite($form, $post->as_array()); @@ -105,7 +105,7 @@ public function index() } else { - $this->template->js = new View('admin/upgrade/upgrade_js'); + $this->themes->js = new View('admin/upgrade/upgrade_js'); } $this->template->content->ftp_server = Settings_Model::get_setting('ftp_server'); diff --git a/application/controllers/admin/users.php b/application/controllers/admin/users.php index d3f2d36cd6..f0d2d0cb27 100755 --- a/application/controllers/admin/users.php +++ b/application/controllers/admin/users.php @@ -35,7 +35,7 @@ public function __construct() public function index() { $this->template->content = new View('admin/users/main'); - $this->template->js = new View('admin/users/users_js'); + $this->themes->js = new View('admin/users/users_js'); // Check, has the form been submitted, if so, setup validation if ($_POST) @@ -337,7 +337,7 @@ public function roles() $this->template->content->form_error = $form_error; $this->template->content->form_saved = $form_saved; $this->template->content->form_action = $form_action; - $this->template->js = new View('admin/users/roles_js'); + $this->themes->js = new View('admin/users/roles_js'); } /** diff --git a/application/controllers/alerts.php b/application/controllers/alerts.php index 37e3621e56..13f544aa8e 100644 --- a/application/controllers/alerts.php +++ b/application/controllers/alerts.php @@ -162,9 +162,6 @@ public function index() $this->themes->js->latitude = $form['alert_lat']; $this->themes->js->longitude = $form['alert_lon']; - // Rebuild Header Block - $this->template->header->header_block = $this->themes->header_block(); - $this->template->footer->footer_block = $this->themes->footer_block(); } @@ -192,10 +189,6 @@ public function confirm() // Hide Mobile $this->template->content->show_mobile = FALSE; } - - // Rebuild Header Block - $this->template->header->header_block = $this->themes->header_block(); - $this->template->footer->footer_block = $this->themes->footer_block(); } @@ -274,9 +267,6 @@ public function verify() $this->template->content->errno = ER_CODE_NOT_FOUND; } - // Rebuild Header Block - $this->template->header->header_block = $this->themes->header_block(); - $this->template->footer->footer_block = $this->themes->footer_block(); } // END function verify @@ -298,9 +288,6 @@ public function unsubscribe($code = NULL) $this->template->content->unsubscribed = TRUE; } - // Rebuild Header Block - $this->template->header->header_block = $this->themes->header_block(); - $this->template->footer->footer_block = $this->themes->footer_block(); } /** diff --git a/application/controllers/contact.php b/application/controllers/contact.php index d14e17c4f5..30fb4f4d17 100644 --- a/application/controllers/contact.php +++ b/application/controllers/contact.php @@ -108,10 +108,6 @@ public function index() $this->template->content->form_error = $form_error; $this->template->content->form_sent = $form_sent; $this->template->content->captcha = $captcha; - - // Rebuild Header Block - $this->template->header->header_block = $this->themes->header_block(); - $this->template->footer->footer_block = $this->themes->footer_block(); } } diff --git a/application/controllers/feeds.php b/application/controllers/feeds.php index 0594eda526..de44c0b1fe 100644 --- a/application/controllers/feeds.php +++ b/application/controllers/feeds.php @@ -77,10 +77,5 @@ public function index() { $this->template->content->pagination_stats = $pagination->total_items.' '.Kohana::lang('ui_admin.feeds'); } - - // Rebuild Header Block - $this->template->header->header_block = $this->themes->header_block(); - $this->template->footer->footer_block = $this->themes->footer_block(); - } } diff --git a/application/controllers/main.php b/application/controllers/main.php index fad69ff0da..3cd27c5eed 100644 --- a/application/controllers/main.php +++ b/application/controllers/main.php @@ -70,12 +70,12 @@ public function __construct() // Themes Helper $this->themes = new Themes(); + $this->themes->requirements(); + $this->themes->frontend = TRUE; $this->themes->api_url = Kohana::config('settings.api_url'); $this->template->header->submit_btn = $this->themes->submit_btn(); $this->template->header->languages = $this->themes->languages(); $this->template->header->search = $this->themes->search(); - $this->template->header->header_block = $this->themes->header_block(); - $this->template->footer->footer_block = $this->themes->footer_block(); // Set Table Prefix $this->table_prefix = Kohana::config('database.default.table_prefix'); @@ -135,6 +135,8 @@ public function __construct() $this->template->header->header_nav->loggedin_user = Auth::instance()->get_user(); } $this->template->header->header_nav->site_name = Kohana::config('settings.site_name'); + + Event::add('ushahidi_filter.view_pre_render.layout', array($this, '_pre_render')); } /** @@ -411,7 +413,12 @@ public function index() // Javascript Header $this->themes->map_enabled = TRUE; - $this->themes->main_page = TRUE; + $this->themes->slider_enabled = TRUE; + + if (Kohana::config('settings.enable_timeline')) + { + $this->themes->timeline_enabled = TRUE; + } // Map Settings $marker_radius = Kohana::config('map.marker_radius'); @@ -442,8 +449,16 @@ public function index() $this->themes->js->active_endDate = $display_endDate; $this->themes->js->blocks_per_row = Kohana::config('settings.blocks_per_row'); - - // Build Header and Footer Blocks + } + + /** + * Trigger themes->requirements() at the last minute + * + * This is in case features are enabled/disabled + */ + public function _pre_render() + { + $this->themes->requirements(); $this->template->header->header_block = $this->themes->header_block(); $this->template->footer->footer_block = $this->themes->footer_block(); } diff --git a/application/controllers/members.php b/application/controllers/members.php index 8c5de566d3..88826e3da9 100644 --- a/application/controllers/members.php +++ b/application/controllers/members.php @@ -58,6 +58,10 @@ public function __construct() url::redirect('/'); } + // Themes Helper + $this->themes = new Themes(); + $this->themes->admin = TRUE; + // Set Table Prefix $this->table_prefix = Kohana::config('database.default.table_prefix'); @@ -65,24 +69,25 @@ public function __construct() // Retrieve Default Settings $this->template->site_name = Kohana::config('settings.site_name'); - $this->template->api_url = Kohana::config('settings.api_url'); + $this->themes->api_url = Kohana::config('settings.api_url'); // Javascript Header - $this->template->map_enabled = FALSE; - $this->template->flot_enabled = FALSE; - $this->template->treeview_enabled = FALSE; - $this->template->protochart_enabled = FALSE; - $this->template->colorpicker_enabled = FALSE; - $this->template->editor_enabled = FALSE; - $this->template->tablerowsort_enabled = FALSE; - $this->template->autocomplete_enabled = FALSE; - $this->template->json2_enabled = FALSE; - $this->template->js = ''; + $this->themes->map_enabled = FALSE; + $this->themes->flot_enabled = FALSE; + $this->themes->treeview_enabled = FALSE; + $this->themes->protochart_enabled = FALSE; + $this->themes->colorpicker_enabled = FALSE; + $this->themes->editor_enabled = FALSE; + $this->themes->tablerowsort_enabled = FALSE; + $this->themes->autocomplete_enabled = FALSE; + $this->themes->json2_enabled = FALSE; + $this->themes->js = ''; + $this->template->form_error = FALSE; // Initialize some variables for raphael impact charts - $this->template->raphael_enabled = FALSE; - $this->template->impact_json = ''; + $this->themes->raphael_enabled = FALSE; + $this->themes->impact_json = ''; // Generate main tab navigation list. $this->template->main_tabs = members::main_tabs(); @@ -100,12 +105,26 @@ public function __construct() $this->template->header_nav->loggedin_user = Auth::instance()->get_user(); } $this->template->header_nav->site_name = Kohana::config('settings.site_name'); - } + + Event::add('ushahidi_filter.view_pre_render.members_layout', array($this, '_pre_render')); + } public function index() { url::redirect('members/dashboard'); } + + /** + * Trigger themes->admin_requirements() at the last minute + * + * This is in case features are enabled/disabled + */ + public function _pre_render() + { + $this->themes->requirements(); + $this->template->header_block = $this->themes->header_block(); + $this->template->footer_block = $this->themes->footer_block(); + } } // End Admin diff --git a/application/controllers/members/alerts.php b/application/controllers/members/alerts.php index b987ad7537..cf61be0ce8 100644 --- a/application/controllers/members/alerts.php +++ b/application/controllers/members/alerts.php @@ -127,6 +127,6 @@ public function index() $this->template->content->total_items = $pagination->total_items; // Javascript Header - $this->template->js = new View('members/alerts_js'); + $this->themes->js = new View('members/alerts_js'); } } diff --git a/application/controllers/members/checkins.php b/application/controllers/members/checkins.php index b2d44e501e..69b3531005 100644 --- a/application/controllers/members/checkins.php +++ b/application/controllers/members/checkins.php @@ -100,7 +100,7 @@ public function index($page = 1) $this->template->content->total_items = $pagination->total_items; // Javascript Header - $this->template->map_enabled = TRUE; - $this->template->js = new View('members/checkins_js'); + $this->themes->map_enabled = TRUE; + $this->themes->js = new View('members/checkins_js'); } } diff --git a/application/controllers/members/dashboard.php b/application/controllers/members/dashboard.php index 853726f895..3b497421c9 100644 --- a/application/controllers/members/dashboard.php +++ b/application/controllers/members/dashboard.php @@ -101,8 +101,8 @@ function index() ); // Javascript Header - $this->template->protochart_enabled = TRUE; - $this->template->js = new View('admin/stats/stats_js'); + $this->themes->protochart_enabled = TRUE; + $this->themes->js = new View('admin/stats/stats_js'); $this->template->content->failure = ''; diff --git a/application/controllers/members/private.php b/application/controllers/members/private.php index 6464c8c65b..431c930209 100644 --- a/application/controllers/members/private.php +++ b/application/controllers/members/private.php @@ -145,7 +145,7 @@ public function index($page = 1) $this->template->content->total_items = $pagination->total_items; // Javascript Header - $this->template->js = new View('members/private_js'); + $this->themes->js = new View('members/private_js'); } /** @@ -258,8 +258,8 @@ public function send() $this->template->content->form_saved = $form_saved; // Javascript Header - $this->template->autocomplete_enabled = TRUE; - $this->template->js = new View('members/private_send_js'); + $this->themes->autocomplete_enabled = TRUE; + $this->themes->js = new View('members/private_send_js'); } /** diff --git a/application/controllers/members/profile.php b/application/controllers/members/profile.php index d46b403fb9..b9f7a2f7b0 100644 --- a/application/controllers/members/profile.php +++ b/application/controllers/members/profile.php @@ -179,7 +179,7 @@ public function index() $this->template->content->yesno_array = array('1'=>utf8::strtoupper(Kohana::lang('ui_main.yes')),'0'=>utf8::strtoupper(Kohana::lang('ui_main.no'))); // Javascript Header - $this->template->colorpicker_enabled = TRUE; + $this->themes->colorpicker_enabled = TRUE; } /** diff --git a/application/controllers/members/reports.php b/application/controllers/members/reports.php index 3ca54745e4..c7bef29d9b 100755 --- a/application/controllers/members/reports.php +++ b/application/controllers/members/reports.php @@ -230,7 +230,7 @@ public function index($page = 1) $this->template->content->status = $status; // Javascript Header - $this->template->js = new View('admin/reports/reports_js'); + $this->themes->js = new View('admin/reports/reports_js'); } @@ -569,37 +569,37 @@ public function edit($id = FALSE, $saved = FALSE) $this->template->content->next_url = $next_url; // Javascript Header - $this->template->map_enabled = TRUE; - $this->template->colorpicker_enabled = TRUE; - $this->template->treeview_enabled = TRUE; - $this->template->json2_enabled = TRUE; + $this->themes->map_enabled = TRUE; + $this->themes->colorpicker_enabled = TRUE; + $this->themes->treeview_enabled = TRUE; + $this->themes->json2_enabled = TRUE; - $this->template->js = new View('reports/submit_edit_js'); - $this->template->js->edit_mode = FALSE; - $this->template->js->default_map = Kohana::config('settings.default_map'); - $this->template->js->default_zoom = Kohana::config('settings.default_zoom'); + $this->themes->js = new View('reports/submit_edit_js'); + $this->themes->js->edit_mode = FALSE; + $this->themes->js->default_map = Kohana::config('settings.default_map'); + $this->themes->js->default_zoom = Kohana::config('settings.default_zoom'); if ( ! $form['latitude'] OR ! $form['latitude']) { - $this->template->js->latitude = Kohana::config('settings.default_lat'); - $this->template->js->longitude = Kohana::config('settings.default_lon'); + $this->themes->js->latitude = Kohana::config('settings.default_lat'); + $this->themes->js->longitude = Kohana::config('settings.default_lon'); } else { - $this->template->js->latitude = $form['latitude']; - $this->template->js->longitude = $form['longitude']; + $this->themes->js->latitude = $form['latitude']; + $this->themes->js->longitude = $form['longitude']; } - $this->template->js->incident_zoom = $form['incident_zoom']; - $this->template->js->geometries = $form['geometry']; + $this->themes->js->incident_zoom = $form['incident_zoom']; + $this->themes->js->geometries = $form['geometry']; // Inline Javascript $this->template->content->date_picker_js = $this->_date_picker_js(); $this->template->content->color_picker_js = $this->_color_picker_js(); // Pack Javascript - $myPacker = new javascriptpacker($this->template->js , 'Normal', FALSE, FALSE); - $this->template->js = $myPacker->pack(); + $myPacker = new javascriptpacker($this->themes->js , 'Normal', FALSE, FALSE); + $this->themes->js = $myPacker->pack(); } diff --git a/application/controllers/page.php b/application/controllers/page.php index 5835cfae5c..86cbb9679c 100644 --- a/application/controllers/page.php +++ b/application/controllers/page.php @@ -51,9 +51,6 @@ public function index($page_id = 1) } $this->template->header->page_title .= $page_title.Kohana::config('settings.title_delimiter'); - - $this->template->header->header_block = $this->themes->header_block(); - $this->template->footer->footer_block = $this->themes->footer_block(); } } diff --git a/application/controllers/profile.php b/application/controllers/profile.php index 91c04428f4..697e31f4f6 100644 --- a/application/controllers/profile.php +++ b/application/controllers/profile.php @@ -34,9 +34,6 @@ public function index() $this->template->content->users = User_Model::get_public_users(); $this->template->header->page_title .= Kohana::lang('ui_main.browse_profiles').Kohana::config('settings.title_delimiter'); - - $this->template->header->header_block = $this->themes->header_block(); - $this->template->footer->footer_block = $this->themes->footer_block(); } /** @@ -104,9 +101,6 @@ public function user() } $this->template->header->page_title .= $user->name.Kohana::config('settings.title_delimiter'); - - $this->template->header->header_block = $this->themes->header_block(); - $this->template->footer->footer_block = $this->themes->footer_block(); } } // End Profile diff --git a/application/controllers/reports.php b/application/controllers/reports.php index 28897a6a45..157d096150 100755 --- a/application/controllers/reports.php +++ b/application/controllers/reports.php @@ -144,9 +144,6 @@ public function index() $this->template->content->report_stats->avg_reports_per_day = $avg_reports_per_day; $this->template->content->report_stats->percent_verified = $percent_verified; $this->template->content->services = Service_Model::get_array(); - - $this->template->header->header_block = $this->themes->header_block(); - $this->template->footer->footer_block = $this->themes->footer_block(); } /** @@ -412,10 +409,6 @@ public function submit($id = FALSE, $saved = FALSE) } $this->themes->js->geometries = $form['geometry']; - - // Rebuild Header Block - $this->template->header->header_block = $this->themes->header_block(); - $this->template->footer->footer_block = $this->themes->footer_block(); } /** @@ -727,10 +720,6 @@ public function view($id = FALSE) // If the Admin is Logged in - Allow for an edit link $this->template->content->logged_in = $this->logged_in; - - // Rebuild Header Block - $this->template->header->header_block = $this->themes->header_block(); - $this->template->footer->footer_block = $this->themes->footer_block(); } /** @@ -740,10 +729,6 @@ public function thanks() { $this->template->header->this_page = 'reports_submit'; $this->template->content = new View('reports/submit_thanks'); - - // Rebuild Header Block - $this->template->header->header_block = $this->themes->header_block(); - $this->template->footer->footer_block = $this->themes->footer_block(); } /** diff --git a/application/controllers/search.php b/application/controllers/search.php index 2288fdab9a..940276e00f 100644 --- a/application/controllers/search.php +++ b/application/controllers/search.php @@ -216,9 +216,5 @@ public function index($page = 1) $this->template->content->search_info = $search_info; $this->template->content->search_results = $html; - - // Rebuild Header Block - $this->template->header->header_block = $this->themes->header_block(); - $this->template->footer->footer_block = $this->themes->footer_block(); } } diff --git a/application/helpers/addon.php b/application/helpers/addon.php index f8c1a98b48..b128813f53 100644 --- a/application/helpers/addon.php +++ b/application/helpers/addon.php @@ -46,7 +46,10 @@ public static function get_addons($type, $include_meta = TRUE) 'Author' => "", 'Author Email' => "", 'Template_Dir' => "", - 'Checkins' => 0 + 'Checkins' => 0, + 'Base Theme' => 'default', + 'CSS' => '', + 'JS' => '', ); } diff --git a/application/helpers/cdn.php b/application/helpers/cdn.php index cc6a82df58..fe61489dfb 100644 --- a/application/helpers/cdn.php +++ b/application/helpers/cdn.php @@ -49,14 +49,14 @@ private static function connection() * @param string $filename Name of the file to be uploaded * @return string */ - public static function upload($filename) + public static function upload($filename, $appendUploadDir = TRUE) { try { self::connection(); // Upload to the CDN and return new filename - return self::$cdn->upload($filename); + return self::$cdn->upload($filename, $appendUploadDir); } catch (Exception $e) { diff --git a/application/helpers/plugin.php b/application/helpers/plugin.php index fe71cda7e0..f94f8a3654 100644 --- a/application/helpers/plugin.php +++ b/application/helpers/plugin.php @@ -10,16 +10,6 @@ */ class plugin_Core { - /** - * @var array - */ - protected static $javascripts = array(); - - /** - * @var array - */ - protected static $stylesheets = array(); - /** * @var array */ @@ -32,12 +22,16 @@ class plugin_Core { */ public static function add_javascript($javascripts = array()) { - if ( ! is_array($javascripts)) - $javascripts = array($javascripts); - - foreach ($javascripts as $key => $javascript) + if (is_array($javascripts)) + { + foreach($javascripts as $javascript) + { + Requirements::js('plugins/'.$javascript.'.js'); + } + } + else { - self::$javascripts[] = $javascript; + Requirements::js('plugins/'.$javascripts.'.js'); } } @@ -49,10 +43,9 @@ public static function add_javascript($javascripts = array()) */ public static function remove_javascript($javascripts = array()) { - foreach (self::$javascripts as $key => $javascript) + foreach ($javascripts as $javascript) { - if (in_array($javascript, $javascripts)) - unset(self::$javascripts[$key]); + Requirements::block('plugins/'.$javascripts.'.js'); } } @@ -64,12 +57,16 @@ public static function remove_javascript($javascripts = array()) */ public static function add_stylesheet($stylesheets = array()) { - if ( ! is_array($stylesheets)) - $stylesheets = array($stylesheets); - - foreach ($stylesheets as $key => $stylesheet) + if (is_array($stylesheets)) { - self::$stylesheets[] = $stylesheet; + foreach($stylesheets as $stylesheet) + { + Requirements::css('plugins/'.$stylesheet.'.css'); + } + } + else + { + Requirements::css('plugins/'.$stylesheets.'.css'); } } @@ -89,43 +86,6 @@ public static function add_sms_provider($sms_providers = array()) } } - /** - * Adds a the stylesheet/javascript to the header of the view file - * - * @param string $type - */ - public static function render($type) - { - $files = $type.'s'; - - $html = ''; - - foreach (self::$$files as $key => $file) - { - switch ($type) - { - case 'stylesheet': - if (substr_compare($file, '.css', -3, 3, FALSE) !== 0) - { - // Add the javascript suffix - $file .= '.css'; - } - $html .= ''; - break; - case 'javascript': - if (substr_compare($file, '.js', -3, 3, FALSE) !== 0) - { - // Add the javascript suffix - $file .= '.js'; - } - $html .= ''; - break; - } - } - - return $html; - } - /** * Rettuns the list of SMS providers * diff --git a/application/helpers/ush_locale.php b/application/helpers/ush_locale.php index 3c3ddd362e..6f55188580 100644 --- a/application/helpers/ush_locale.php +++ b/application/helpers/ush_locale.php @@ -213,6 +213,22 @@ public static function language($iso639) } } + /** + * Is a language written Right-to-left + * @param $locale + */ + public static function is_rtl_language($locale = NULL) + { + // Check for text direction override + if (Kohana::config('locale.force_text_direction') == 'rtl') return TRUE; + if (Kohana::config('locale.force_text_direction') == 'ltr') return FALSE; + + // Check for special translation string 'ui_main.text_direction' + if (Kohana::lang('core.text_direction', $locale) == 'rtl') return TRUE; + + return FALSE; + } + /** * @param string ISO-3166 country code */ @@ -530,9 +546,8 @@ public static function get_i18n($refresh = FALSE) /** * Detect language from GET param, session or settings. - * @param string */ - public static function detect_language($language = FALSE) + public static function detect_language() { // Locale form submitted? if (isset($_GET['l']) && !empty($_GET['l'])) diff --git a/application/hooks/2_settings.php b/application/hooks/2_settings.php index 6516640890..1a680f59e2 100644 --- a/application/hooks/2_settings.php +++ b/application/hooks/2_settings.php @@ -42,10 +42,9 @@ $default_map = isset($settings['default_map']) ? $settings['default_map'] : 'osm_mapnik'; $map_layer = map::base($default_map); -if (isset($map_layer->api_url) AND $map_layer->api_url != '') +if (! empty($map_layer->api_url)) { - Kohana::config_set('settings.api_url', - ""); + Kohana::config_set('settings.api_url', $map_layer->api_url); } // And in case you want to display all maps on one page... @@ -54,9 +53,9 @@ { if (empty($layer->api_url)) continue; // Add to array, use url as key to avoid dupes - $api_url_all[$layer->api_url] = ''; + $api_url_all[$layer->api_url] = $layer->api_url; } -Kohana::config_set('settings.api_url_all', implode("\n",$api_url_all)); +Kohana::config_set('settings.api_url_all', $api_url_all); // Additional Mime Types (KMZ/KML) Kohana::config_set('mimes.kml', array('text/xml')); diff --git a/application/hooks/register_themes.php b/application/hooks/register_themes.php index f71eb79045..f2373ac0bc 100755 --- a/application/hooks/register_themes.php +++ b/application/hooks/register_themes.php @@ -14,6 +14,13 @@ */ class register_themes { + + protected $themes = array(); + protected $loaded_themes = array(); + + protected $theme_js = array(); + protected $theme_css = array(); + /** * Adds the register method to load after system.ready */ @@ -22,68 +29,9 @@ public function __construct() // Hook into routing if (Kohana::config('config.installer_check') == FALSE OR file_exists(DOCROOT."application/config/database.php")) { - Event::add('system.ready', array($this, 'register')); + Event::add('system.ready', array('Themes', 'register_theme')); } } - - /** - * Loads ushahidi themes - */ - public function register() - { - // Array to hold all the CSS files - $theme_css = array(); - // Array to hold all the Javascript files - $theme_js = array(); - - // 1. Load the default theme - Kohana::config_set('core.modules', array_merge(array(THEMEPATH."default"), - Kohana::config("core.modules"))); - $theme_css[] = url::file_loc('css')."themes/default/css/style.css"; - - // 2. Extend the default theme - $theme = THEMEPATH.Kohana::config("settings.site_style"); - if ( Kohana::config("settings.site_style") != "default" ) - { - Kohana::config_set('core.modules', array_merge(array($theme), - Kohana::config("core.modules"))); - - if ( is_dir($theme.'/css') ) - { - $css = dir($theme.'/css'); // Load all the themes css files - while (($css_file = $css->read()) !== FALSE) - if (preg_match('/\.css/i', $css_file)) - { - $theme_css[] = url::file_loc('css')."themes/".Kohana::config("settings.site_style")."/css/".$css_file; - } - } - - if ( is_dir($theme.'/js') ) - { - $js = dir($theme.'/js'); // Load all the themes js files - while (($js_file = $js->read()) !== FALSE) - if (preg_match('/\.js/i', $js_file)) - { - $theme_js[] = url::base()."themes/".Kohana::config("settings.site_style")."/js/".$js_file; - } - } - } - - // 3. Find and add hooks - // We need to manually include the hook file for each theme - if (file_exists($theme.'/hooks')) - { - $d = dir($theme.'/hooks'); // Load all the hooks - while (($entry = $d->read()) !== FALSE) - if ($entry[0] != '.') - { - include $theme.'/hooks/'.$entry; - } - } - - Kohana::config_set('settings.site_style_css',$theme_css); - Kohana::config_set('settings.site_style_js',$theme_js); - } } new register_themes; \ No newline at end of file diff --git a/application/libraries/CSSmin.php b/application/libraries/CSSmin.php new file mode 100644 index 0000000000..6741eeeccf --- /dev/null +++ b/application/libraries/CSSmin.php @@ -0,0 +1,741 @@ +run($css); + } + + /** + * @param bool|int $raise_php_limits + * If true, PHP settings will be raised if needed + */ + public function __construct($raise_php_limits = TRUE) + { + // Set suggested PHP limits + $this->memory_limit = 128 * 1048576; // 128MB in bytes + $this->max_execution_time = 60; // 1 min + $this->pcre_backtrack_limit = 1000 * 1000; + $this->pcre_recursion_limit = 500 * 1000; + + $this->raise_php_limits = (bool) $raise_php_limits; + } + + /** + * Minify a string of CSS + * @param string $css + * @param int|bool $linebreak_pos + * @return string + */ + public function run($css = '', $linebreak_pos = FALSE) + { + if (empty($css)) { + return ''; + } + + if ($this->raise_php_limits) { + $this->do_raise_php_limits(); + } + + $this->comments = array(); + $this->preserved_tokens = array(); + + $start_index = 0; + $length = strlen($css); + + $css = $this->extract_data_urls($css); + + // collect all comment blocks... + while (($start_index = $this->index_of($css, '/*', $start_index)) >= 0) { + $end_index = $this->index_of($css, '*/', $start_index + 2); + if ($end_index < 0) { + $end_index = $length; + } + $comment_found = $this->str_slice($css, $start_index + 2, $end_index); + $this->comments[] = $comment_found; + $comment_preserve_string = self::COMMENT . (count($this->comments) - 1) . '___'; + $css = $this->str_slice($css, 0, $start_index + 2) . $comment_preserve_string . $this->str_slice($css, $end_index); + // Set correct start_index: Fixes issue #2528130 + $start_index = $end_index + 2 + strlen($comment_preserve_string) - strlen($comment_found); + } + + // preserve strings so their content doesn't get accidentally minified + $css = preg_replace_callback('/(?:"(?:[^\\\\"]|\\\\.|\\\\)*")|'."(?:'(?:[^\\\\']|\\\\.|\\\\)*')/S", array($this, 'replace_string'), $css); + + // Let's divide css code in chunks of 25.000 chars aprox. + // Reason: PHP's PCRE functions like preg_replace have a "backtrack limit" + // of 100.000 chars by default (php < 5.3.7) so if we're dealing with really + // long strings and a (sub)pattern matches a number of chars greater than + // the backtrack limit number (i.e. /(.*)/s) PCRE functions may fail silently + // returning NULL and $css would be empty. + $charset = ''; + $charset_regexp = '/@charset [^;]+;/i'; + $css_chunks = array(); + $css_chunk_length = 25000; // aprox size, not exact + $start_index = 0; + $i = $css_chunk_length; // save initial iterations + $l = strlen($css); + + + // if the number of characters is 25000 or less, do not chunk + if ($l <= $css_chunk_length) { + $css_chunks[] = $css; + } else { + // chunk css code securely + while ($i < $l) { + $i += 50; // save iterations. 500 checks for a closing curly brace } + if ($l - $start_index <= $css_chunk_length || $i >= $l) { + $css_chunks[] = $this->str_slice($css, $start_index); + break; + } + if ($css[$i - 1] === '}' && $i - $start_index > $css_chunk_length) { + // If there are two ending curly braces }} separated or not by spaces, + // join them in the same chunk (i.e. @media blocks) + $next_chunk = substr($css, $i); + if (preg_match('/^\s*\}/', $next_chunk)) { + $i = $i + $this->index_of($next_chunk, '}') + 1; + } + + $css_chunks[] = $this->str_slice($css, $start_index, $i); + $start_index = $i; + } + } + } + + // Minify each chunk + for ($i = 0, $n = count($css_chunks); $i < $n; $i++) { + $css_chunks[$i] = $this->minify($css_chunks[$i], $linebreak_pos); + // Keep the first @charset at-rule found + if (empty($charset) && preg_match($charset_regexp, $css_chunks[$i], $matches)) { + $charset = $matches[0]; + } + // Delete all @charset at-rules + $css_chunks[$i] = preg_replace($charset_regexp, '', $css_chunks[$i]); + } + + // Update the first chunk and push the charset to the top of the file. + $css_chunks[0] = $charset . $css_chunks[0]; + + return implode('', $css_chunks); + } + + /** + * Sets the memory limit for this script + * @param int|string $limit + */ + public function set_memory_limit($limit) + { + $this->memory_limit = $this->normalize_int($limit); + } + + /** + * Sets the maximum execution time for this script + * @param int|string $seconds + */ + public function set_max_execution_time($seconds) + { + $this->max_execution_time = (int) $seconds; + } + + /** + * Sets the PCRE backtrack limit for this script + * @param int $limit + */ + public function set_pcre_backtrack_limit($limit) + { + $this->pcre_backtrack_limit = (int) $limit; + } + + /** + * Sets the PCRE recursion limit for this script + * @param int $limit + */ + public function set_pcre_recursion_limit($limit) + { + $this->pcre_recursion_limit = (int) $limit; + } + + /** + * Try to configure PHP to use at least the suggested minimum settings + */ + private function do_raise_php_limits() + { + $php_limits = array( + 'memory_limit' => $this->memory_limit, + 'max_execution_time' => $this->max_execution_time, + 'pcre.backtrack_limit' => $this->pcre_backtrack_limit, + 'pcre.recursion_limit' => $this->pcre_recursion_limit + ); + + // If current settings are higher respect them. + foreach ($php_limits as $name => $suggested) { + $current = $this->normalize_int(ini_get($name)); + // memory_limit exception: allow -1 for "no memory limit". + if ($current > -1 && ($suggested == -1 || $current < $suggested)) { + ini_set($name, $suggested); + } + } + } + + /** + * Does bulk of the minification + * @param string $css + * @param int|bool $linebreak_pos + * @return string + */ + private function minify($css, $linebreak_pos) + { + // strings are safe, now wrestle the comments + for ($i = 0, $max = count($this->comments); $i < $max; $i++) { + + $token = $this->comments[$i]; + $placeholder = '/' . self::COMMENT . $i . '___/'; + + // ! in the first position of the comment means preserve + // so push to the preserved tokens keeping the ! + if (substr($token, 0, 1) === '!') { + $this->preserved_tokens[] = $token; + $token_tring = self::TOKEN . (count($this->preserved_tokens) - 1) . '___'; + $css = preg_replace($placeholder, $token_tring, $css, 1); + // Preserve new lines for /*! important comments + $css = preg_replace('/\s*[\n\r\f]+\s*(\/\*'. $token_tring .')/S', self::NL.'$1', $css); + $css = preg_replace('/('. $token_tring .'\*\/)\s*[\n\r\f]+\s*/S', '$1'.self::NL, $css); + continue; + } + + // \ in the last position looks like hack for Mac/IE5 + // shorten that to /*\*/ and the next one to /**/ + if (substr($token, (strlen($token) - 1), 1) === '\\') { + $this->preserved_tokens[] = '\\'; + $css = preg_replace($placeholder, self::TOKEN . (count($this->preserved_tokens) - 1) . '___', $css, 1); + $i = $i + 1; // attn: advancing the loop + $this->preserved_tokens[] = ''; + $css = preg_replace('/' . self::COMMENT . $i . '___/', self::TOKEN . (count($this->preserved_tokens) - 1) . '___', $css, 1); + continue; + } + + // keep empty comments after child selectors (IE7 hack) + // e.g. html >/**/ body + if (strlen($token) === 0) { + $start_index = $this->index_of($css, $this->str_slice($placeholder, 1, -1)); + if ($start_index > 2) { + if (substr($css, $start_index - 3, 1) === '>') { + $this->preserved_tokens[] = ''; + $css = preg_replace($placeholder, self::TOKEN . (count($this->preserved_tokens) - 1) . '___', $css, 1); + } + } + } + + // in all other cases kill the comment + $css = preg_replace('/\/\*' . $this->str_slice($placeholder, 1, -1) . '\*\//', '', $css, 1); + } + + + // Normalize all whitespace strings to single spaces. Easier to work with that way. + $css = preg_replace('/\s+/', ' ', $css); + + // Shorten & preserve calculations calc(...) since spaces are important + $css = preg_replace_callback('/calc(\((?:[^\(\)]+|(?1))*\))/i', array($this, 'replace_calc'), $css); + + // Replace positive sign from numbers preceded by : or a white-space before the leading space is removed + // +1.2em to 1.2em, +.8px to .8px, +2% to 2% + $css = preg_replace('/((? -9.0 to -9 + $css = preg_replace('/((?\+\(\)\]\~\=,])/', '$1', $css); + $css = preg_replace('/' . self::CLASSCOLON . '/', ':', $css); + + // retain space for special IE6 cases + $css = preg_replace('/\:first\-(line|letter)(\{|,)/i', ':first-$1 $2', $css); + + // no space after the end of a preserved comment + $css = preg_replace('/\*\/ /', '*/', $css); + + // Put the space back in some cases, to support stuff like + // @media screen and (-webkit-min-device-pixel-ratio:0){ + $css = preg_replace('/\band\(/i', 'and (', $css); + + // Remove the spaces after the things that should not have spaces after them. + $css = preg_replace('/([\!\{\}\:;\>\+\(\[\~\=,])\s+/S', '$1', $css); + + // remove unnecessary semicolons + $css = preg_replace('/;+\}/', '}', $css); + + // Fix for issue: #2528146 + // Restore semicolon if the last property is prefixed with a `*` (lte IE7 hack) + // to avoid issues on Symbian S60 3.x browsers. + $css = preg_replace('/(\*[a-z0-9\-]+\s*\:[^;\}]+)(\})/', '$1;$2', $css); + + // Replace 0 length units 0(px,em,%) with 0. + $css = preg_replace('/((?compress_hex_colors($css); + + // border: none to border:0, outline: none to outline:0 + $css = preg_replace('/(border\-?(?:top|right|bottom|left|)|outline)\:none(;|\})/ieS', "strtolower('$1:0$2')", $css); + + // shorter opacity IE filter + $css = preg_replace('/progid\:DXImageTransform\.Microsoft\.Alpha\(Opacity\=/i', 'alpha(opacity=', $css); + + // Remove empty rules. + $css = preg_replace('/[^\};\{\/]+\{\}/S', '', $css); + + // Some source control tools don't like it when files containing lines longer + // than, say 8000 characters, are checked in. The linebreak option is used in + // that case to split long lines after a specific column. + if ($linebreak_pos !== FALSE && (int) $linebreak_pos >= 0) { + $linebreak_pos = (int) $linebreak_pos; + $start_index = $i = 0; + while ($i < strlen($css)) { + $i++; + if ($css[$i - 1] === '}' && $i - $start_index > $linebreak_pos) { + $css = $this->str_slice($css, 0, $i) . "\n" . $this->str_slice($css, $i); + $start_index = $i; + } + } + } + + // Replace multiple semi-colons in a row by a single one + // See SF bug #1980989 + $css = preg_replace('/;;+/', ';', $css); + + // Restore new lines for /*! important comments + $css = preg_replace('/'. self::NL .'/', "\n", $css); + + // restore preserved comments and strings + for ($i = 0, $max = count($this->preserved_tokens); $i < $max; $i++) { + $css = preg_replace('/' . self::TOKEN . $i . '___/', $this->preserved_tokens[$i], $css, 1); + } + + // Trim the final string (for any leading or trailing white spaces) + return trim($css); + } + + /** + * Utility method to replace all data urls with tokens before we start + * compressing, to avoid performance issues running some of the subsequent + * regexes against large strings chunks. + * + * @param string $css + * @return string + */ + private function extract_data_urls($css) + { + // Leave data urls alone to increase parse performance. + $max_index = strlen($css) - 1; + $append_index = $index = $last_index = $offset = 0; + $sb = array(); + $pattern = '/url\(\s*(["\']?)data\:/i'; + + // Since we need to account for non-base64 data urls, we need to handle + // ' and ) being part of the data string. Hence switching to indexOf, + // to determine whether or not we have matching string terminators and + // handling sb appends directly, instead of using matcher.append* methods. + + while (preg_match($pattern, $css, $m, 0, $offset)) { + $index = $this->index_of($css, $m[0], $offset); + $last_index = $index + strlen($m[0]); + $start_index = $index + 4; // "url(".length() + $end_index = $last_index - 1; + $terminator = $m[1]; // ', " or empty (not quoted) + $found_terminator = FALSE; + + if (strlen($terminator) === 0) { + $terminator = ')'; + } + + while ($found_terminator === FALSE && $end_index+1 <= $max_index) { + $end_index = $this->index_of($css, $terminator, $end_index + 1); + + // endIndex == 0 doesn't really apply here + if ($end_index > 0 && substr($css, $end_index - 1, 1) !== '\\') { + $found_terminator = TRUE; + if (')' != $terminator) { + $end_index = $this->index_of($css, ')', $end_index); + } + } + } + + // Enough searching, start moving stuff over to the buffer + $sb[] = $this->substring($css, $append_index, $index); + + if ($found_terminator) { + $token = $this->substring($css, $start_index, $end_index); + $token = preg_replace('/\s+/', '', $token); + $this->preserved_tokens[] = $token; + + $preserver = 'url(' . self::TOKEN . (count($this->preserved_tokens) - 1) . '___)'; + $sb[] = $preserver; + + $append_index = $end_index + 1; + } else { + // No end terminator found, re-add the whole match. Should we throw/warn here? + $sb[] = $this->substring($css, $index, $last_index); + $append_index = $last_index; + } + + $offset = $last_index; + } + + $sb[] = $this->substring($css, $append_index); + + return implode('', $sb); + } + + /** + * Utility method to compress hex color values of the form #AABBCC to #ABC or short color name. + * + * DOES NOT compress CSS ID selectors which match the above pattern (which would break things). + * e.g. #AddressForm { ... } + * + * DOES NOT compress IE filters, which have hex color values (which would break things). + * e.g. filter: chroma(color="#FFFFFF"); + * + * DOES NOT compress invalid hex values. + * e.g. background-color: #aabbccdd + * + * @param string $css + * @return string + */ + private function compress_hex_colors($css) + { + // Look for hex colors inside { ... } (to avoid IDs) and which don't have a =, or a " in front of them (to avoid filters) + $pattern = '/(\=\s*?["\']?)?#([0-9a-f])([0-9a-f])([0-9a-f])([0-9a-f])([0-9a-f])([0-9a-f])(\}|[^0-9a-f{][^{]*?\})/iS'; + $_index = $index = $last_index = $offset = 0; + $sb = array(); + // See: http://ajaxmin.codeplex.com/wikipage?title=CSS%20Colors + $short_safe = array( + '#808080' => 'gray', + '#008000' => 'green', + '#800000' => 'maroon', + '#000080' => 'navy', + '#808000' => 'olive', + '#800080' => 'purple', + '#c0c0c0' => 'silver', + '#008080' => 'teal', + '#f00' => 'red' + ); + + while (preg_match($pattern, $css, $m, 0, $offset)) { + $index = $this->index_of($css, $m[0], $offset); + $last_index = $index + strlen($m[0]); + $is_filter = (bool) $m[1]; + + $sb[] = $this->substring($css, $_index, $index); + + if ($is_filter) { + // Restore, maintain case, otherwise filter will break + $sb[] = $m[1] . '#' . $m[2] . $m[3] . $m[4] . $m[5] . $m[6] . $m[7]; + } else { + if (strtolower($m[2]) == strtolower($m[3]) && + strtolower($m[4]) == strtolower($m[5]) && + strtolower($m[6]) == strtolower($m[7])) { + // Compress. + $hex = '#' . strtolower($m[3] . $m[5] . $m[7]); + } else { + // Non compressible color, restore but lower case. + $hex = '#' . strtolower($m[2] . $m[3] . $m[4] . $m[5] . $m[6] . $m[7]); + } + // replace Hex colors to short safe color names + $sb[] = array_key_exists($hex, $short_safe) ? $short_safe[$hex] : $hex; + } + + $_index = $offset = $last_index - strlen($m[8]); + } + + $sb[] = $this->substring($css, $_index); + + return implode('', $sb); + } + + /* CALLBACKS + * --------------------------------------------------------------------------------------------- + */ + + private function replace_string($matches) + { + $match = $matches[0]; + $quote = substr($match, 0, 1); + // Must use addcslashes in PHP to avoid parsing of backslashes + $match = addcslashes($this->str_slice($match, 1, -1), '\\'); + + // maybe the string contains a comment-like substring? + // one, maybe more? put'em back then + if (($pos = $this->index_of($match, self::COMMENT)) >= 0) { + for ($i = 0, $max = count($this->comments); $i < $max; $i++) { + $match = preg_replace('/' . self::COMMENT . $i . '___/', $this->comments[$i], $match, 1); + } + } + + // minify alpha opacity in filter strings + $match = preg_replace('/progid\:DXImageTransform\.Microsoft\.Alpha\(Opacity\=/i', 'alpha(opacity=', $match); + + $this->preserved_tokens[] = $match; + return $quote . self::TOKEN . (count($this->preserved_tokens) - 1) . '___' . $quote; + } + + private function replace_colon($matches) + { + return preg_replace('/\:/', self::CLASSCOLON, $matches[0]); + } + + private function replace_calc($matches) + { + $this->preserved_tokens[] = preg_replace('/\s?([\*\/\(\),])\s?/', '$1', $matches[0]); + return self::TOKEN . (count($this->preserved_tokens) - 1) . '___'; + } + + private function rgb_to_hex($matches) + { + // Support for percentage values rgb(100%, 0%, 45%); + if ($this->index_of($matches[1], '%') >= 0){ + $rgbcolors = explode(',', str_replace('%', '', $matches[1])); + for ($i = 0; $i < count($rgbcolors); $i++) { + $rgbcolors[$i] = $this->round_number(floatval($rgbcolors[$i]) * 2.55); + } + } else { + $rgbcolors = explode(',', $matches[1]); + } + + // Values outside the sRGB color space should be clipped (0-255) + for ($i = 0; $i < count($rgbcolors); $i++) { + $rgbcolors[$i] = $this->clamp_number(intval($rgbcolors[$i], 10), 0, 255); + $rgbcolors[$i] = sprintf("%02x", $rgbcolors[$i]); + } + + // Fix for issue #2528093 + if (!preg_match('/[\s\,\);\}]/', $matches[2])){ + $matches[2] = ' ' . $matches[2]; + } + + return '#' . implode('', $rgbcolors) . $matches[2]; + } + + private function hsl_to_hex($matches) + { + $values = explode(',', str_replace('%', '', $matches[1])); + $h = floatval($values[0]); + $s = floatval($values[1]); + $l = floatval($values[2]); + + // Wrap and clamp, then fraction! + $h = ((($h % 360) + 360) % 360) / 360; + $s = $this->clamp_number($s, 0, 100) / 100; + $l = $this->clamp_number($l, 0, 100) / 100; + + if ($s == 0) { + $r = $g = $b = $this->round_number(255 * $l); + } else { + $v2 = $l < 0.5 ? $l * (1 + $s) : ($l + $s) - ($s * $l); + $v1 = (2 * $l) - $v2; + $r = $this->round_number(255 * $this->hue_to_rgb($v1, $v2, $h + (1/3))); + $g = $this->round_number(255 * $this->hue_to_rgb($v1, $v2, $h)); + $b = $this->round_number(255 * $this->hue_to_rgb($v1, $v2, $h - (1/3))); + } + + return $this->rgb_to_hex(array('', $r.','.$g.','.$b, $matches[2])); + } + + /* HELPERS + * --------------------------------------------------------------------------------------------- + */ + + private function hue_to_rgb($v1, $v2, $vh) + { + $vh = $vh < 0 ? $vh + 1 : ($vh > 1 ? $vh - 1 : $vh); + if ($vh * 6 < 1) return $v1 + ($v2 - $v1) * 6 * $vh; + if ($vh * 2 < 1) return $v2; + if ($vh * 3 < 2) return $v1 + ($v2 - $v1) * ((2/3) - $vh) * 6; + return $v1; + } + + private function round_number($n) + { + return intval(floor(floatval($n) + 0.5), 10); + } + + private function clamp_number($n, $min, $max) + { + return min(max($n, $min), $max); + } + + /** + * PHP port of Javascript's "indexOf" function for strings only + * Author: Tubal Martin http://blog.margenn.com + * + * @param string $haystack + * @param string $needle + * @param int $offset index (optional) + * @return int + */ + private function index_of($haystack, $needle, $offset = 0) + { + $index = strpos($haystack, $needle, $offset); + + return ($index !== FALSE) ? $index : -1; + } + + /** + * PHP port of Javascript's "substring" function + * Author: Tubal Martin http://blog.margenn.com + * Tests: http://margenn.com/tubal/substring/ + * + * @param string $str + * @param int $from index + * @param int|bool $to index (optional) + * @return string + */ + private function substring($str, $from = 0, $to = FALSE) + { + if ($to !== FALSE) { + if ($from == $to || ($from <= 0 && $to < 0)) { + return ''; + } + + if ($from > $to) { + $from_copy = $from; + $from = $to; + $to = $from_copy; + } + } + + if ($from < 0) { + $from = 0; + } + + $substring = ($to === FALSE) ? substr($str, $from) : substr($str, $from, $to - $from); + return ($substring === FALSE) ? '' : $substring; + } + + /** + * PHP port of Javascript's "slice" function for strings only + * Author: Tubal Martin http://blog.margenn.com + * Tests: http://margenn.com/tubal/str_slice/ + * + * @param string $str + * @param int $start index + * @param int|bool $end index (optional) + * @return string + */ + private function str_slice($str, $start = 0, $end = FALSE) + { + if ($end !== FALSE && ($start < 0 || $end <= 0)) { + $max = strlen($str); + + if ($start < 0) { + if (($start = $max + $start) < 0) { + return ''; + } + } + + if ($end < 0) { + if (($end = $max + $end) < 0) { + return ''; + } + } + + if ($end <= $start) { + return ''; + } + } + + $slice = ($end === FALSE) ? substr($str, $start) : substr($str, $start, $end - $start); + return ($slice === FALSE) ? '' : $slice; + } + + /** + * Convert strings like "64M" or "30" to int values + * @param mixed $size + * @return int + */ + private function normalize_int($size) + { + if (is_string($size)) { + switch (substr($size, -1)) { + case 'M': case 'm': return $size * 1048576; + case 'K': case 'k': return $size * 1024; + case 'G': case 'g': return $size * 1073741824; + } + } + + return (int) $size; + } +} \ No newline at end of file diff --git a/application/libraries/Cloudfiles.php b/application/libraries/Cloudfiles.php index 571440b604..b2f59927c6 100644 --- a/application/libraries/Cloudfiles.php +++ b/application/libraries/Cloudfiles.php @@ -96,14 +96,14 @@ public function authenticate() } // $file must be the absolute path to the file - public function upload($filename) + public function upload($filename, $appendUploadDir = TRUE) { $this->authenticate(); $local_directory = Kohana::config('upload.directory', TRUE); $local_directory = rtrim($local_directory, '/').'/'; - $fullpath = $local_directory.$filename; + $fullpath = $appendUploadDir ? $local_directory.$filename : DOCROOT.$filename; // Put this in a special directory based on subdomain if subdomain is set $dir = $this->_special_dir(); @@ -123,7 +123,7 @@ public function upload($filename) $uri = $container->make_public(); // Return the file path URL - return $file->public_ssl_uri(); + return (Kohana::config('config.external_site_protocol') == 'https') ? $file->public_ssl_uri() : $file->public_uri(); } public function delete($url) diff --git a/application/libraries/JSMin.php b/application/libraries/JSMin.php new file mode 100644 index 0000000000..ee1b442bce --- /dev/null +++ b/application/libraries/JSMin.php @@ -0,0 +1,386 @@ + + * @copyright 2002 Douglas Crockford
+ * array('//symlink' => '/real/target/path') // unix
+ * array('//static' => 'D:\\staticStorage') // Windows
+ *
+ *
+ * @return string
+ */
+ public static function rewrite($css, $currentDir, $docRoot = null, $symlinks = array())
+ {
+ self::$_docRoot = self::_realpath(
+ $docRoot ? $docRoot : $_SERVER['DOCUMENT_ROOT']
+ );
+ self::$_currentDir = self::_realpath($currentDir);
+ self::$_symlinks = array();
+
+ // normalize symlinks
+ foreach ($symlinks as $link => $target) {
+ $link = ($link === '//')
+ ? self::$_docRoot
+ : str_replace('//', self::$_docRoot . '/', $link);
+ $link = strtr($link, '/', DIRECTORY_SEPARATOR);
+ self::$_symlinks[$link] = self::_realpath($target);
+ }
+
+ self::$debugText .= "docRoot : " . self::$_docRoot . "\n"
+ . "currentDir : " . self::$_currentDir . "\n";
+ if (self::$_symlinks) {
+ self::$debugText .= "symlinks : " . var_export(self::$_symlinks, 1) . "\n";
+ }
+ self::$debugText .= "\n";
+
+ $css = self::_trimUrls($css);
+
+ // rewrite
+ $css = preg_replace_callback('/@import\\s+([\'"])(.*?)[\'"]/'
+ ,array(self::$className, '_processUriCB'), $css);
+ $css = preg_replace_callback('/url\\(\\s*([^\\)\\s]+)\\s*\\)/'
+ ,array(self::$className, '_processUriCB'), $css);
+
+ return $css;
+ }
+
+ /**
+ * In CSS content, prepend a path to relative URIs
+ *
+ * @param string $css
+ *
+ * @param string $path The path to prepend.
+ *
+ * @return string
+ */
+ public static function prepend($css, $path)
+ {
+ self::$_prependPath = $path;
+
+ $css = self::_trimUrls($css);
+
+ // append
+ $css = preg_replace_callback('/@import\\s+([\'"])(.*?)[\'"]/'
+ ,array(self::$className, '_processUriCB'), $css);
+ $css = preg_replace_callback('/url\\(\\s*([^\\)\\s]+)\\s*\\)/'
+ ,array(self::$className, '_processUriCB'), $css);
+
+ self::$_prependPath = null;
+ return $css;
+ }
+
+ /**
+ * Get a root relative URI from a file relative URI
+ *
+ *
+ * Minify_CSS_UriRewriter::rewriteRelative(
+ * '../img/hello.gif'
+ * , '/home/user/www/css' // path of CSS file
+ * , '/home/user/www' // doc root
+ * );
+ * // returns '/img/hello.gif'
+ *
+ * // example where static files are stored in a symlinked directory
+ * Minify_CSS_UriRewriter::rewriteRelative(
+ * 'hello.gif'
+ * , '/var/staticFiles/theme'
+ * , '/home/user/www'
+ * , array('/home/user/www/static' => '/var/staticFiles')
+ * );
+ * // returns '/static/theme/hello.gif'
+ *
+ *
+ * @param string $uri file relative URI
+ *
+ * @param string $realCurrentDir realpath of the current file's directory.
+ *
+ * @param string $realDocRoot realpath of the site document root.
+ *
+ * @param array $symlinks (default = array()) If the file is stored in
+ * a symlink-ed directory, provide an array of link paths to
+ * real target paths, where the link paths "appear" to be within the document
+ * root. E.g.:
+ *
+ * array('/home/foo/www/not/real/path' => '/real/target/path') // unix
+ * array('C:\\htdocs\\not\\real' => 'D:\\real\\target\\path') // Windows
+ *
+ *
+ * @return string
+ */
+ public static function rewriteRelative($uri, $realCurrentDir, $realDocRoot, $symlinks = array())
+ {
+ // prepend path with current dir separator (OS-independent)
+ $path = strtr($realCurrentDir, '/', DIRECTORY_SEPARATOR)
+ . DIRECTORY_SEPARATOR . strtr($uri, '/', DIRECTORY_SEPARATOR);
+
+ self::$debugText .= "file-relative URI : {$uri}\n"
+ . "path prepended : {$path}\n";
+
+ // "unresolve" a symlink back to doc root
+ foreach ($symlinks as $link => $target) {
+ if (0 === strpos($path, $target)) {
+ // replace $target with $link
+ $path = $link . substr($path, strlen($target));
+
+ self::$debugText .= "symlink unresolved : {$path}\n";
+
+ break;
+ }
+ }
+ // strip doc root
+ $path = substr($path, strlen($realDocRoot));
+
+ self::$debugText .= "docroot stripped : {$path}\n";
+
+ // fix to root-relative URI
+ $uri = strtr($path, '/\\', '//');
+ $uri = self::removeDots($uri);
+
+ self::$debugText .= "traversals removed : {$uri}\n\n";
+
+ return $uri;
+ }
+
+ /**
+ * Remove instances of "./" and "../" where possible from a root-relative URI
+ *
+ * @param string $uri
+ *
+ * @return string
+ */
+ public static function removeDots($uri)
+ {
+ $uri = str_replace('/./', '/', $uri);
+ // inspired by patch from Oleg Cherniy
+ do {
+ $uri = preg_replace('@/[^/]+/\\.\\./@', '/', $uri, 1, $changed);
+ } while ($changed);
+ return $uri;
+ }
+
+ /**
+ * Defines which class to call as part of callbacks, change this
+ * if you extend Minify_CSS_UriRewriter
+ *
+ * @var string
+ */
+ protected static $className = 'Minify_CSS_UriRewriter';
+
+ /**
+ * Get realpath with any trailing slash removed. If realpath() fails,
+ * just remove the trailing slash.
+ *
+ * @param string $path
+ *
+ * @return mixed path with no trailing slash
+ */
+ protected static function _realpath($path)
+ {
+ $realPath = realpath($path);
+ if ($realPath !== false) {
+ $path = $realPath;
+ }
+ return rtrim($path, '/\\');
+ }
+
+ /**
+ * Directory of this stylesheet
+ *
+ * @var string
+ */
+ private static $_currentDir = '';
+
+ /**
+ * DOC_ROOT
+ *
+ * @var string
+ */
+ private static $_docRoot = '';
+
+ /**
+ * directory replacements to map symlink targets back to their
+ * source (within the document root) E.g. '/var/www/symlink' => '/var/realpath'
+ *
+ * @var array
+ */
+ private static $_symlinks = array();
+
+ /**
+ * Path to prepend
+ *
+ * @var string
+ */
+ private static $_prependPath = null;
+
+ /**
+ * @param string $css
+ *
+ * @return string
+ */
+ private static function _trimUrls($css)
+ {
+ return preg_replace('/
+ url\\( # url(
+ \\s*
+ ([^\\)]+?) # 1 = URI (assuming does not contain ")")
+ \\s*
+ \\) # )
+ /x', 'url($1)', $css);
+ }
+
+ /**
+ * @param array $m
+ *
+ * @return string
+ */
+ private static function _processUriCB($m)
+ {
+ // $m matched either '/@import\\s+([\'"])(.*?)[\'"]/' or '/url\\(\\s*([^\\)\\s]+)\\s*\\)/'
+ $isImport = ($m[0][0] === '@');
+ // determine URI and the quote character (if any)
+ if ($isImport) {
+ $quoteChar = $m[1];
+ $uri = $m[2];
+ } else {
+ // $m[1] is either quoted or not
+ $quoteChar = ($m[1][0] === "'" || $m[1][0] === '"')
+ ? $m[1][0]
+ : '';
+ $uri = ($quoteChar === '')
+ ? $m[1]
+ : substr($m[1], 1, strlen($m[1]) - 2);
+ }
+ // analyze URI
+ if ('/' !== $uri[0] // root-relative
+ && false === strpos($uri, '//') // protocol (non-data)
+ && 0 !== strpos($uri, 'data:') // data protocol
+ ) {
+ // URI is file-relative: rewrite depending on options
+ if (self::$_prependPath === null) {
+ $uri = self::rewriteRelative($uri, self::$_currentDir, self::$_docRoot, self::$_symlinks);
+ } else {
+ $uri = self::$_prependPath . $uri;
+ if ($uri[0] === '/') {
+ $root = '';
+ $rootRelative = $uri;
+ $uri = $root . self::removeDots($rootRelative);
+ } elseif (preg_match('@^((https?\:)?//([^/]+))/@', $uri, $m) && (false !== strpos($m[3], '.'))) {
+ $root = $m[1];
+ $rootRelative = substr($uri, strlen($root));
+ $uri = $root . self::removeDots($rootRelative);
+ }
+ }
+ }
+ return $isImport
+ ? "@import {$quoteChar}{$uri}{$quoteChar}"
+ : "url({$quoteChar}{$uri}{$quoteChar})";
+ }
+}
diff --git a/application/libraries/Requirements.php b/application/libraries/Requirements.php
new file mode 100644
index 0000000000..82a9bc1ff1
--- /dev/null
+++ b/application/libraries/Requirements.php
@@ -0,0 +1,1177 @@
+set_combined_files_enabled($enable);
+ }
+
+ /**
+ * Checks whether combining of css/javascript files is enabled.
+ * @return boolean
+ */
+ public static function get_combined_files_enabled() {
+ return self::backend()->get_combined_files_enabled();
+ }
+
+ /**
+ * Set the relative folder e.g. "assets" for where to store combined files
+ * @param string $folder Path to folder
+ */
+ public static function set_combined_files_folder($folder) {
+ self::backend()->setCombinedFilesFolder($folder);
+ }
+
+ /**
+ * Set whether we want to suffix requirements with the time /
+ * location on to the requirements
+ *
+ * @param bool
+ */
+ public static function set_suffix_requirements($var) {
+ self::backend()->set_suffix_requirements($var);
+ }
+
+ /**
+ * Return whether we want to suffix requirements
+ *
+ * @return bool
+ */
+ public static function get_suffix_requirements() {
+ return self::backend()->get_suffix_requirements();
+ }
+
+ /**
+ * Instance of requirements for storage
+ *
+ * @var Requirements
+ */
+ private static $backend = null;
+
+ public static function backend() {
+ if(!self::$backend) {
+ self::$backend = new Requirements_Backend();
+ }
+ return self::$backend;
+ }
+
+ /**
+ * Setter method for changing the Requirements backend
+ *
+ * @param Requirements $backend
+ */
+ public static function set_backend(Requirements_Backend $backend) {
+ self::$backend = $backend;
+ }
+
+ /**
+ * Register the given javascript file as required.
+ *
+ * See {@link Requirements_Backend::javascript()} for more info
+ *
+ */
+ static function js($file, $uniquenessID = null) {
+ self::backend()->js($file, $uniquenessID);
+ }
+
+ /**
+ * Add the javascript code to the header of the page
+ *
+ * See {@link Requirements_Backend::customJS()} for more info
+ * @param script The script content
+ * @param uniquenessID Use this to ensure that pieces of code only get added once.
+ */
+ static function customJS($script, $uniquenessID) {
+ self::backend()->customJS($script, $uniquenessID);
+ }
+
+ /**
+ * Include custom CSS styling to the header of the page.
+ *
+ * See {@link Requirements_Backend::customCSS()}
+ *
+ * @param string $script CSS selectors as a string (without \n";
+ }
+ }
+
+ return $content;
+ }
+
+ /**
+ * Finds the path for specified file.
+ *
+ * @param string $fileOrUrl
+ * @param string $type file type ie. css or js
+ * @return string|boolean
+ */
+ protected function path_for_file($fileOrUrl, $type) {
+ if(preg_match('/^http[s]?/', $fileOrUrl)) {
+ return $fileOrUrl;
+ } else {
+ // Split query from filename
+ $suffix = '';
+ if(strpos($fileOrUrl, '?') !== false) {
+ $suffix = substr($fileOrUrl, strpos($fileOrUrl, '?')+1);
+ $fileOrUrl = substr($fileOrUrl, 0, strpos($fileOrUrl, '?'));
+ }
+
+ if (file_exists(DOCROOT . $fileOrUrl)) {
+ // Check for RTL replacements
+ if ($type == 'css' AND ush_locale::is_rtl_language())
+ {
+ $rtlFile = substr($fileOrUrl, 0, strpos($fileOrUrl, ".$type")) . "-rtl" . substr($fileOrUrl, strpos($fileOrUrl, ".$type"));
+ if (file_exists(DOCROOT . $rtlFile))
+ {
+ $fileOrUrl = $rtlFile;
+ }
+ }
+
+ // Get url prefix, either site base url or CDN url
+ $prefix = url::file_loc($type);
+
+ $mtimesuffix = "?";
+ if($this->suffix_requirements) {
+ $mtimesuffix .= "m=" . filemtime(DOCROOT . $fileOrUrl);
+ $suffix = '&'.$suffix;
+ }
+ return "{$prefix}{$fileOrUrl}{$mtimesuffix}{$suffix}";
+ }
+ }
+ Kohana::log('alert', "Requirements: file $fileOrUrl not found");
+ return false;
+ }
+
+ /**
+ * Concatenate several css or javascript files into a single dynamically generated
+ * file. This increases performance by fewer HTTP requests.
+ *
+ * The combined file is only included if one or more of the individual files was included
+ * with Requirements::js() or Requirements::css() already.
+ *
+ * The combined file is regenerated based on every file modification time.
+ * Optionally a rebuild can be triggered by appending ?flush=1 to the URL.
+ * If all files to be combined are javascript, we use the external JSMin library
+ * to minify the javascript. This can be controlled by {@link $combine_js_with_jsmin}.
+ *
+ * CAUTION: You're responsible for ensuring that the load order for combined files
+ * is retained - otherwise combining javascript files can lead to functional errors
+ * in the javascript logic, and combining css can lead to wrong styling inheritance.
+ * Depending on the javascript logic, you also have to ensure that files are not included
+ * in more than one combine_files() call.
+ *
+ * Best practice is to include every javascript file in exactly *one* combine_files()
+ * directive to avoid the issues mentioned above - this is enforced by this function.
+ *
+ * CAUTION: Combining CSS Files discards any "media" information.
+ *
+ * Example for combined JavaScript:
+ *
+ * Requirements::combine_files(
+ * 'foobar.js',
+ * array(
+ * 'mysite/javascript/foo.js',
+ * 'mysite/javascript/bar.js',
+ * 'baz.min' => 'mysite/javascript/baz.min',
+ * )
+ * );
+ *
+ *
+ * Example for combined CSS:
+ *
+ * Requirements::combine_files(
+ * 'foobar.css',
+ * array(
+ * 'mysite/javascript/foo.css',
+ * 'mysite/javascript/bar.css',
+ * )
+ * );
+ *
+ *
+ * @see http://code.google.com/p/jsmin-php/
+ *
+ * @todo Should we enforce unique inclusion of files, or leave it to the developer? Can auto-detection cause breaks?
+ *
+ * @param string $combinedFileName Filename of the combined file
+ * @param array $files Array of filenames relative to the webroot
+ */
+ function combine_files($combinedFileName, $files) {
+ $type = stripos($combinedFileName, '.js') ? 'js' : 'css';
+
+ // duplicate check
+ foreach($this->combine_files[$type] as $_combinedFileName => $_files) {
+ $duplicates = array_intersect($_files, $files);
+ if($duplicates && $combinedFileName != $_combinedFileName) {
+ Kohana::log('info', "Requirements_Backend::combine_files(): Already included files " . implode(',', $duplicates) . " in combined file '{$_combinedFileName}'");
+ return false;
+ }
+ }
+
+ // If the $files array is indexed, generate uniquenessID from last part of filename
+ if (array_values($files) === $files)
+ {
+ $new_files = array();
+ foreach($files as $file)
+ {
+ $uniquenessID = substr( $file, strrpos( $file, '/' ) +1 );
+ $new_files[$uniquenessID] = $file;
+ }
+ $files = $new_files;
+ }
+
+ $this->combine_files[$type][$combinedFileName] = $files;
+ }
+
+ /**
+ * Returns all combined files.
+ * @return array
+ */
+ function get_combine_files() {
+ return $this->combine_files;
+ }
+
+ /**
+ * Deletes all dynamically generated combined files from the filesystem.
+ *
+ * @param string $combinedFileName If left blank, all combined files are deleted.
+ */
+ function delete_combined_files($combinedFileName = null) {
+ $combinedFiles = ($combinedFileName) ? array($combinedFileName => null) : array_merge($this->combine_files['css'], $this->combine_files['js']);
+ $combinedFolder = DOCROOT . $this->getCombinedFilesFolder();
+ foreach($combinedFiles as $combinedFile => $sourceItems) {
+ $filePath = $combinedFolder . '/' . $combinedFile;
+ if(file_exists($filePath)) {
+ unlink($filePath);
+ }
+ }
+ }
+
+ function clear_combined_files() {
+ $this->combine_files = array('js' => array(), 'css' => array());
+ }
+
+ /**
+ * See {@link combine_files()}
+ *
+ */
+ function process_combined_files($type = 'all') {
+ if( !$this->combined_files_enabled) {
+ return;
+ }
+
+ switch ($type)
+ {
+ case 'js':
+ $this->_process_combined_files('js');
+ break;
+ case 'css':
+ $this->_process_combined_files('css');
+ break;
+ case 'all':
+ default:
+ $this->_process_combined_files('js');
+ $this->_process_combined_files('css');
+ break;
+ }
+ }
+
+ /**
+ * See {@link combine_files()}
+ *
+ */
+ private function _process_combined_files($type) {
+ // Make a map of files that could be potentially combined
+ $combinerCheck = array();
+ foreach($this->combine_files[$type] as $combinedFile => $sourceItems) {
+ foreach($sourceItems as $id => $sourceItem) {
+ if(isset($combinerCheck[$sourceItem]) && $combinerCheck[$sourceItem] != $combinedFile){
+ Kohana::log('alert',"Requirements_Backend::process_combined_files - file '$sourceItem' appears in two combined files:" . " '{$combinerCheck[$sourceItem]}' and '$combinedFile'");
+ }
+ $combinerCheck[$sourceItem] = $combinedFile;
+ $combinerCheck[$id] = $combinedFile;
+ }
+ }
+
+ // Work out the relative URL for the combined files from the base folder
+ $combinedFilesFolder = ($this->getCombinedFilesFolder()) ? ($this->getCombinedFilesFolder() . '/') : '';
+
+ // Figure out which ones apply to this pageview
+ $combinedFiles = array();
+ $newRequirements = array();
+ foreach($this->$type as $id => $params) {
+ $file = ($type == 'js') ? $params : $params['file'];
+ if(isset($combinerCheck[$file])) {
+ $newRequirements[$combinerCheck[$file]] = ($type == 'js') ? $combinedFilesFolder . $combinerCheck[$file] : array('file' => $combinedFilesFolder . $combinerCheck[$file]);
+ $combinedFiles[$combinerCheck[$file]] = true;
+ } elseif(isset($combinerCheck[$id])) {
+ $newRequirements[$combinerCheck[$id]] = ($type == 'js') ? $combinedFilesFolder . $combinerCheck[$id] : array('file' => $combinedFilesFolder . $combinerCheck[$id]);
+ $combinedFiles[$combinerCheck[$id]] = true;
+ } else {
+ $newRequirements[$id] = $params;
+ }
+ }
+
+ // Process the combined files
+ $base = DOCROOT;
+ foreach(array_diff_key($combinedFiles, $this->blocked) as $combinedFile => $dummy) {
+ $fileList = $this->combine_files[$type][$combinedFile];
+ $combinedFilePath = $base . $combinedFilesFolder . $combinedFile;
+
+ // Check for RTL alternatives
+ if ($type == 'css' AND ush_locale::is_rtl_language())
+ {
+ $has_rtl_files = FALSE;
+ foreach($fileList as $index => $file)
+ {
+ $rtlFile = substr($file, 0, strpos($file, ".$type")) . "-rtl" . substr($file, strpos($file, ".$type"));
+ if (file_exists(DOCROOT . $rtlFile))
+ {
+ $fileList[$index] = $rtlFile;
+ $has_rtl_files = TRUE;
+ }
+ }
+
+ // Update combined files details, only if the include RTL alternatives
+ // We store the RTL version separate from the LTR version, so we don't regenerate every time someone changes language
+ if ($has_rtl_files)
+ {
+ $combinedFile = substr($combinedFile, 0, -4).'-rtl.css';
+ $combinedFilePath = $base . $combinedFilesFolder . $combinedFile;
+ $newRequirements[$combinedFile] = ($type == 'js') ? $combinedFilesFolder . $combinedFile : array('file' => $combinedFilesFolder . $combinedFile);
+ }
+ }
+
+ // Make the folder if necessary
+ if(!file_exists(dirname($combinedFilePath))) {
+ mkdir(dirname($combinedFilePath));
+ }
+
+ // If the file isn't writebale, don't even bother trying to make the combined file
+ // Complex test because is_writable fails if the file doesn't exist yet.
+ if((file_exists($combinedFilePath) && !is_writable($combinedFilePath)) ||
+ (!file_exists($combinedFilePath) && !is_writable(dirname($combinedFilePath)))) {
+ Kohana::log('alert', "Requirements_Backend::process_combined_files(): Couldn't create '$combinedFilePath'");
+ continue;
+ }
+
+ // Determine if we need to build the combined include
+ if(file_exists($combinedFilePath) && !isset($_GET['flush'])) {
+ // file exists, check modification date of every contained file
+ $srcLastMod = 0;
+ foreach($fileList as $file) {
+ $srcLastMod = max(filemtime($base . $file), $srcLastMod);
+ }
+ $refresh = $srcLastMod > filemtime($combinedFilePath);
+ } else {
+ // file doesn't exist, or refresh was explicitly required
+ $refresh = true;
+ }
+
+ if(!$refresh) continue;
+
+ $combinedData = "";
+ foreach(array_diff($fileList, $this->blocked) as $id => $file) {
+ $fileContent = file_get_contents($base . $file);
+
+ // if we have a javascript file and jsmin is enabled, minify the content
+ if($type == 'js' && $this->combine_js_with_jsmin) {
+ $fileContent = JSMin::minify($fileContent);
+ }
+
+ if($type == 'css') {
+ // Rewrite urls in css to be relative to the docroot
+ $fileContent = Minify_CSS_UriRewriter::rewrite($fileContent, pathinfo($base . $file, PATHINFO_DIRNAME), DOCROOT);
+ // compress css (if enabled)
+ if ($this->combine_css_with_cssmin)
+ {
+ $fileContent = CSSMin::go($fileContent);
+ }
+ }
+
+ // write a header comment for each file for easier identification and debugging
+ // also the semicolon between each file is required for jQuery to be combinable properly
+ $combinedData .= "/****** FILE: $file *****/\n" . $fileContent . "\n" . ($type == 'js' ? ';' : '') . "\n";
+ }
+
+ $successfulWrite = false;
+ $fh = fopen($combinedFilePath, 'wb');
+ if($fh) {
+ if(fwrite($fh, $combinedData) == strlen($combinedData)) $successfulWrite = true;
+ fclose($fh);
+ unset($fh);
+ }
+
+ // Should we push this to the CDN too?
+ if (Kohana::config("cdn.cdn_store_dynamic_content") AND Kohana::config("requirements.cdn_store_combined_files"))
+ {
+ $cdn_combined_path = cdn::upload($combinedFilesFolder . $combinedFile, FALSE);
+ }
+
+ // Unsuccessful write - just include the regular JS files, rather than the combined one
+ if(!$successfulWrite) {
+ Kohana::log('alert', "Requirements_Backend::process_combined_files(): Couldn't create '$combinedFilePath'");
+ continue;
+ }
+ }
+
+ // @todo Alters the original information, which means you can't call this
+ // method repeatedly - it will behave different on the second call!
+ $this->$type = $newRequirements;
+ }
+
+ function get_custom_scripts() {
+ $requirements = "";
+
+ if($this->customJS) {
+ foreach($this->customJS as $script) {
+ $requirements .= "$script\n";
+ }
+ }
+
+ return $requirements;
+ }
+
+ /**
+ * @see Requirements::themedCSS()
+ */
+ public function themedCSS($name, $module = null, $media = null) {
+ $this->css($this->themedCSSPath($name, $module), $name, $media);
+ return;
+ }
+
+ /**
+ * @see Requirements::ieCSS()
+ */
+ public function ieCSS($version, $name, $media = null) {
+ $this->customHeadTags("",'iecss-'.$name);
+ return;
+ }
+
+ /**
+ * @see Requirements::ieThemedCSS()
+ */
+ public function ieThemedCSS($version, $name, $module = null, $media = null) {
+ $this->ieCSS($version, $this->themedCSSPath($name, $module), $media, FALSE);
+ return;
+ }
+
+ private function themedCSSPath($name, $module = null)
+ {
+ // try to include from a loaded theme
+ foreach (Themes::loaded_themes() as $theme)
+ {
+ $path = THEMEPATH . "$theme/css/$name.css";
+ if (file_exists($path)) {
+ return "themes/$theme/css/$name.css";
+ }
+ }
+
+ // Try to include from fall back module
+ if ($module AND file_exists(DOCROOT . "$module/css/$name.css")) {
+ return "$module/css/$name.css";
+ }
+
+ // Try to include from global media
+ if (file_exists(DOCROOT . "media/css/$name.css")) {
+ return "media/css/$name.css";
+ }
+ }
+
+ function debug() {
+ Debug::show($this->js);
+ Debug::show($this->css);
+ Debug::show($this->customCSS);
+ Debug::show($this->customJS);
+ Debug::show($this->customHeadTags);
+ Debug::show($this->combine_files);
+ }
+
+}
diff --git a/application/libraries/Themes.php b/application/libraries/Themes.php
index 11ca87666c..f2facca2ea 100644
--- a/application/libraries/Themes.php
+++ b/application/libraries/Themes.php
@@ -16,16 +16,27 @@
class Themes_Core {
+ public $frontend = false;
+ public $admin = false;
+
public $map_enabled = false;
public $api_url = null;
- public $main_page = false;
public $this_page = false;
public $treeview_enabled = false;
public $validator_enabled = false;
public $photoslider_enabled = false;
public $colorpicker_enabled = false;
+ public $datepicker_enabled = false;
public $editor_enabled = false;
- public $site_style = false;
+ public $protochart_enabled = false;
+ public $raphael_enabled = false;
+ public $tablerowsort_enabled = false;
+ public $json2_enabled = false;
+ public $hovertip_enabled = false;
+ public $slider_enabled = false;
+ public $timeline_enabled = false;
+
+ // Custom JS to be added
public $js = null;
public $css_url = null;
@@ -38,10 +49,6 @@ public function __construct()
// Load Session
$this->session = Session::instance();
-
- // Grab the proper URL for the css and js files
- $this->css_url = url::file_loc('css');
- $this->js_url = url::file_loc('js');
}
/**
@@ -50,13 +57,27 @@ public function __construct()
*/
public function header_block()
{
- $content = Kohana::config("globalcode.head").
- $this->_header_css().
- $this->_header_feeds().
- $this->_header_js();
-
+ $content = '';
+ // For backward compatibility render Requirements here rather than in the view
+ if (Kohana::config('requirements.write_js_to_body'))
+ {
+ $content .= Requirements::render('css');
+ $content .= Requirements::render('headtags');
+ }
+ else
+ {
+ $content .= Requirements::render();
+ }
+
// Filter::header_block - Modify Header Block
+ if ($this->admin)
+ {
+ Event::run('ushahidi_filter.admin_header_block', $content);
+ }
+ elseif ($this->frontend)
+ {
Event::run('ushahidi_filter.header_block', $content);
+ }
return $content;
}
@@ -67,171 +88,298 @@ public function header_block()
*/
public function admin_header_block()
{
- $content = Kohana::config("globalcode.head");
-
- // Filter::admin_header_block - Modify Admin Header Block
- Event::run('ushahidi_filter.admin_header_block', $content);
-
- return $content;
+ $this->header_block();
}
/**
- * Css Items
+ * CSS/JS requirements
*/
- private function _header_css()
+ public function requirements()
{
- $core_css = "";
- $core_css .= html::stylesheet($this->css_url."media/css/jquery-ui-themeroller", "", TRUE);
+ Requirements::customHeadTags(Kohana::config("globalcode.head"),'globalcode-head');
+
+ Requirements::js("media/js/jquery.js");
+ Requirements::js("media/js/jquery.ui.min.js");
+ //Requirements::js(Kohana::config('core.site_protocol')."://ajax.googleapis.com/ajax/libs/jqueryui/1.8.13/jquery-ui.min.js");
+ Requirements::js("media/js/jquery.pngFix.pack.js");
+ Requirements::js("media/js/jquery.timeago.js");
+
+ Requirements::css("media/css/jquery-ui-themeroller.css");
+
+ Requirements::js('media/js/global.js');
+ Requirements::css('media/css/global.css');
- foreach (Kohana::config("settings.site_style_css") as $theme_css)
+ if ($this->map_enabled)
{
- $core_css .= html::stylesheet($theme_css,"",TRUE);
+ Requirements::js("media/js/OpenLayers.js");
+ Requirements::js("media/js/ushahidi.js");
+ Requirements::js($this->api_url);
+ Requirements::customJS("OpenLayers.ImgPath = '".url::file_loc('js')."media/img/openlayers/"."';",'openlayers-imgpath');
+
+ Requirements::css("media/css/openlayers.css");
+ }
+
+ if ($this->hovertip_enabled)
+ {
+ Requirements::js('media/js/jquery.hovertip-1.0.js');
+ Requirements::css('media/css/jquery.hovertip-1.0.css', '');
+ Requirements::customJS(
+ "$(function() {
+ if($('.tooltip[title]') != null)
+ $('.tooltip[title]').hovertip();
+ });",
+ 'tooltip-js'
+ );
+ }
+
+ if ($this->slider_enabled)
+ {
+ Requirements::js('media/js/selectToUISlider.jQuery.js');
}
- $core_css .= "";
- $core_css .= "";
- $core_css .= "";
-
- if ($this->map_enabled)
+ if ($this->timeline_enabled)
{
- $core_css .= html::stylesheet($this->css_url."media/css/openlayers","",TRUE);
+ Requirements::js("media/js/jquery.jqplot.min.js");
+ Requirements::css("media/css/jquery.jqplot.min.css");
+ Requirements::js("media/js/jqplot.dateAxisRenderer.min.js");
}
if ($this->treeview_enabled)
{
- $core_css .= html::stylesheet($this->css_url."media/css/jquery.treeview","",TRUE);
+ Requirements::css("media/css/jquery.treeview.css");
+ Requirements::js("media/js/jquery.treeview.js");
}
-
- if ($this->photoslider_enabled)
+
+ // Load ProtoChart
+ if ($this->protochart_enabled)
{
- $core_css .= html::stylesheet($this->css_url."media/css/picbox/picbox","",TRUE);
+ Requirements::customJS("jQuery.noConflict()", 'jquery-noconflict');
+ Requirements::js('media/js/protochart/prototype.js');
+ Requirements::customHeadTags(
+ '',
+ 'ie-excanvas-compressed');
+ Requirements::js('media/js/protochart/ProtoChart.js');
}
-
- if ($this->colorpicker_enabled)
+
+ // Load Raphael
+ if ($this->raphael_enabled)
{
- $core_css .= html::stylesheet($this->css_url."media/css/colorpicker","",TRUE);
+ // The only reason we include prototype is to keep the div element naming convention consistent
+ //Requirements::js('media/js/protochart/prototype.js');
+ Requirements::js('media/js/raphael.js');
+ Requirements::customJS('var impact_json = '.$this->impact_json .';','impact_json');
+ Requirements::js('media/js/raphael-ushahidi-impact.js');
}
- if ($this->site_style AND $this->site_style != "default")
+ if ($this->validator_enabled)
{
- $core_css .= html::stylesheet($this->css_url."themes/".$site_style."/style.css");
+ Requirements::js("media/js/jquery.validate.min.js");
}
- $core_css .= html::stylesheet($this->css_url."media/css/global","",TRUE);
- $core_css .= html::stylesheet($this->css_url."media/css/jquery.jqplot.min", "", TRUE);
-
- // Render CSS
- $plugin_css = plugin::render('stylesheet');
-
- return $core_css.$plugin_css;
+ if ($this->photoslider_enabled)
+ {
+ Requirements::css("media/css/picbox/picbox.css");
+ Requirements::js("media/js/picbox.js");
}
- /**
- * Javascript Files and Inline JS
- */
- private function _header_js()
- {
- $core_js = "";
- if ($this->map_enabled)
+ if ($this->colorpicker_enabled)
{
- $core_js .= html::script($this->js_url."media/js/OpenLayers", TRUE);
- $core_js .= "";
- $core_js .= html::script($this->js_url."media/js/ushahidi", TRUE);
+ Requirements::css("media/css/colorpicker.css");
+ Requirements::js("media/js/colorpicker.js");
}
- $core_js .= html::script($this->js_url."media/js/jquery", TRUE);
- //$core_js .= html::script($this->js_url."media/js/jquery.ui.min", TRUE);
- $core_js .= html::script(Kohana::config('core.site_protocol')."://ajax.googleapis.com/ajax/libs/jqueryui/1.8.13/jquery-ui.min.js", TRUE);
- $core_js .= html::script($this->js_url."media/js/jquery.pngFix.pack", TRUE);
- $core_js .= html::script($this->js_url."media/js/jquery.timeago", TRUE);
-
- if ($this->map_enabled)
+ // Load jwysiwyg
+ if ($this->editor_enabled)
{
-
- $core_js .= $this->api_url;
-
- if ($this->main_page || $this->this_page == "alerts")
+ Requirements::css('media/js/jwysiwyg/jwysiwyg/jquery.wysiwyg.css');
+ if (Kohana::config("cdn.cdn_ignore_jwysiwyg") == TRUE)
{
- $core_js .= html::script($this->js_url."media/js/selectToUISlider.jQuery", TRUE);
+ Requirements::js(url::file_loc('ignore').'media/js/jwysiwyg/jwysiwyg/jquery.wysiwyg.js'); // not sure what the hell to do about this
}
-
- if ($this->main_page)
+ else
{
- // Notes: E.Kala =5?' class="ui-datepicker-week-end"':"")+'>'+ -t[u]+" | "}C+=E+"=q.getTime()&&u.getTime()<=z.getTime()?" "+this._currentClass:"")+(u.getTime()==b.getTime()?" ui-datepicker-today":""))+'"'+((!H||v)&&I[2]?' title="'+I[2]+'"':"")+(K?"":" onclick=\"DP_jQuery.datepicker._selectDay('#"+a.id+"',"+j+","+s+', this);return false;"')+">"+(H?v?u.getDate(): -" ":K?''+u.getDate()+"":'=q.getTime()&&u.getTime()<=z.getTime()?" ui-state-active":"")+'" href="#">'+u.getDate()+"")+" | ";u.setDate(u.getDate()+1);u=this._daylightSavingAdjust(u)}C+=N+""}j++;if(j>11){j=0;s++}C+="
---|
'+this._get(a,"weekHeader")+" | ":"";for(var S=0;S<7;S++){var T=(S+y)%7;R+="=5?' class="ui-datepicker-week-end"':"")+">"+''+C[T]+" | "}Q+=R+"'+this._get(a,"calculateWeek")(Y)+" | ":"";for(var S=0;S<7;S++){var ba=F?F.apply(a.input?a.input[0]:null,[Y]):[!0,""],bb=Y.getMonth()!=n,bc=bb&&!H||!ba[0]||l&&Y"+(bb&&!G?" ":bc?''+Y.getDate()+"":''+Y.getDate()+"")+" | ",Y.setDate(Y.getDate()+1),Y=this._daylightSavingAdjust(Y)}Q+=_+""}n++,n>11&&(n=0,o++),Q+="
---|