~xibo-maintainers/xibo/tempel

« back to all changes in this revision

Viewing changes to lib/Widget/ForecastIo.php

  • Committer: Dan Garner
  • Date: 2016-02-18 16:07:16 UTC
  • mfrom: (454.4.137)
  • Revision ID: git-v1:8867f12675bc9e0e67e7e622c80da7471b9f294a
Merge pull request #139 from dasgarner/feature/nested-display-groups

Feature/nested display groups

Show diffs side-by-side

added added

removed removed

Lines of Context:
23
23
 
24
24
use GuzzleHttp\Client;
25
25
use GuzzleHttp\Exception\RequestException;
26
 
use Respect\Validation\Validator as v;
27
26
use Xibo\Entity\Media;
28
27
use Xibo\Exception\NotFoundException;
29
 
use Xibo\Exception\XiboException;
30
 
use Xibo\Factory\ModuleFactory;
 
28
use Xibo\Factory\DisplayFactory;
 
29
use Xibo\Factory\MediaFactory;
 
30
use Xibo\Helper\Cache;
 
31
use Xibo\Helper\Config;
 
32
use Xibo\Helper\Date;
 
33
use Xibo\Helper\Log;
 
34
use Xibo\Helper\Sanitize;
 
35
use Xibo\Helper\Theme;
31
36
 
32
 
/**
33
 
 * Class ForecastIo
34
 
 * Weather module powered by the DarkSky API
35
 
 * @package Xibo\Widget
36
 
 */
37
37
class ForecastIo extends ModuleWidget
38
38
{
39
 
    const API_ENDPOINT = 'https://api.darksky.net/forecast/';
 
39
    const API_ENDPOINT = 'https://api.forecast.io/forecast/';
40
40
 
41
41
    private $resourceFolder;
42
42
    protected $codeSchemaVersion = 1;
43
43
 
44
 
    /**
45
 
     * ForecastIo constructor.
46
 
     */
47
 
    public function init()
 
44
    public function __construct()
48
45
    {
49
 
        $this->resourceFolder = PROJECT_ROOT . '/modules/forecastio/player';
 
46
        $this->resourceFolder = PROJECT_ROOT . '/web/modules/forecastio';
50
47
 
51
 
        // Initialise extra validation rules
52
 
        v::with('Xibo\\Validation\\Rules\\');
 
48
        parent::__construct();
53
49
    }
54
50
 
55
51
    /**
56
52
     * Install or Update this module
57
 
     * @param ModuleFactory $moduleFactory
58
53
     */
59
 
    public function installOrUpdate($moduleFactory)
 
54
    public function installOrUpdate()
60
55
    {
61
56
        if ($this->module == null) {
62
57
            // Install
63
 
            $module = $moduleFactory->createEmpty();
64
 
            $module->name = 'Weather';
 
58
            $module = new \Xibo\Entity\Module();
 
59
            $module->name = 'Forecast IO';
65
60
            $module->type = 'forecastio';
66
61
            $module->class = 'Xibo\Widget\ForecastIo';
67
 
            $module->description = 'Weather Powered by DarkSky';
 
62
            $module->description = 'Weather forecasting from Forecast IO';
68
63
            $module->imageUri = 'forms/library.gif';
69
64
            $module->enabled = 1;
70
65
            $module->previewEnabled = 1;
85
80
 
86
81
    public function installFiles()
87
82
    {
88
 
        $this->mediaFactory->createModuleSystemFile(PROJECT_ROOT . '/modules/vendor/jquery-1.11.1.min.js')->save();
89
 
        $this->mediaFactory->createModuleSystemFile(PROJECT_ROOT . '/modules/xibo-layout-scaler.js')->save();
90
 
        $this->mediaFactory->createModuleSystemFile(PROJECT_ROOT . '/modules/xibo-image-render.js')->save();
91
 
        $this->mediaFactory->createModuleSystemFile(PROJECT_ROOT . '/modules/vendor/bootstrap.min.css')->save();
 
83
        MediaFactory::createModuleSystemFile(PROJECT_ROOT . '/web/modules/vendor/jquery-1.11.1.min.js')->save();
 
84
        MediaFactory::createModuleSystemFile(PROJECT_ROOT . '/web/modules/xibo-layout-scaler.js')->save();
92
85
 
93
 
        foreach ($this->mediaFactory->createModuleFileFromFolder($this->resourceFolder) as $media) {
 
86
        foreach (MediaFactory::createModuleFileFromFolder($this->resourceFolder) as $media) {
94
87
            /* @var Media $media */
95
88
            $media->save();
96
89
        }
110
103
    public function settings()
111
104
    {
112
105
        // Process any module settings you asked for.
113
 
        $apiKey = $this->getSanitizer()->getString('apiKey');
 
106
        $apiKey = Sanitize::getString('apiKey');
114
107
 
115
108
        if ($apiKey == '')
116
109
            throw new \InvalidArgumentException(__('Missing API Key'));
117
110
 
118
111
        $this->module->settings['apiKey'] = $apiKey;
119
 
        $this->module->settings['cachePeriod'] = $this->getSanitizer()->getInt('cachePeriod', 300);
 
112
        $this->module->settings['cachePeriod'] = Sanitize::getInt('cachePeriod', 300);
 
113
    }
 
114
 
 
115
    /**
 
116
     * Loads templates for this module
 
117
     */
 
118
    private function loadTemplates()
 
119
    {
 
120
        // Scan the folder for template files
 
121
        foreach (glob(PROJECT_ROOT . '/modules/forecastio/*.template.json') as $template) {
 
122
            // Read the contents, json_decode and add to the array
 
123
            $this->module->settings['templates'][] = json_decode(file_get_contents($template), true);
 
124
        }
 
125
 
 
126
        Log::debug(count($this->module->settings['templates']));
 
127
    }
 
128
 
 
129
    /**
 
130
     * Templates available
 
131
     * @return array
 
132
     */
 
133
    public function templatesAvailable()
 
134
    {
 
135
        if (!isset($this->module->settings['templates']))
 
136
            $this->loadTemplates();
 
137
 
 
138
        return $this->module->settings['templates'];
120
139
    }
121
140
 
122
141
    public function validate()
123
142
    {
124
 
        
125
 
        if($this->getOption('overrideTemplate') == 0 && ( $this->getOption('templateId') == '' || $this->getOption('templateId') == null) )
126
 
            throw new \InvalidArgumentException(__('Please choose a template'));
127
 
            
128
143
        if ($this->getUseDuration() == 1 && $this->getDuration() == 0)
129
144
            throw new \InvalidArgumentException(__('Please enter a duration'));
130
 
 
131
 
        if ($this->getOption('useDisplayLocation') == 0) {
132
 
            // Validate lat/long
133
 
            if (!v::latitude()->validate($this->getOption('latitude')))
134
 
                throw new \InvalidArgumentException(__('The latitude entered is not valid.'));
135
 
 
136
 
            if (!v::longitude()->validate($this->getOption('longitude')))
137
 
                throw new \InvalidArgumentException(__('The longitude entered is not valid.'));
138
 
        }
139
145
    }
140
146
 
141
147
    /**
142
 
     * Adds a Weather Widget
143
 
     * @SWG\Post(
144
 
     *  path="/playlist/widget/forecastIo/{playlistId}",
145
 
     *  operationId="WidgetWeatherAdd",
146
 
     *  tags={"widget"},
147
 
     *  summary="Add a Weather Widget",
148
 
     *  description="Add a new Weather Widget to the specified playlist",
149
 
     *  @SWG\Parameter(
150
 
     *      name="playlistId",
151
 
     *      in="path",
152
 
     *      description="The playlist ID to add a Weather widget",
153
 
     *      type="integer",
154
 
     *      required=true
155
 
     *   ),
156
 
     *  @SWG\Parameter(
157
 
     *      name="name",
158
 
     *      in="formData",
159
 
     *      description="Optional Widget Name",
160
 
     *      type="string",
161
 
     *      required=false
162
 
     *  ),
163
 
     *  @SWG\Parameter(
164
 
     *      name="duration",
165
 
     *      in="formData",
166
 
     *      description="Widget Duration",
167
 
     *      type="integer",
168
 
     *      required=false
169
 
     *  ),
170
 
     *  @SWG\Parameter(
171
 
     *      name="useDuration",
172
 
     *      in="formData",
173
 
     *      description="(0, 1) Select 1 only if you will provide duration parameter as well",
174
 
     *      type="integer",
175
 
     *      required=false
176
 
     *  ),
177
 
     *  @SWG\Parameter(
178
 
     *      name="useDisplayLocation",
179
 
     *      in="formData",
180
 
     *      description="Flag (0, 1) Use the location configured on display",
181
 
     *      type="integer",
182
 
     *      required=true
183
 
     *   ),
184
 
     *  @SWG\Parameter(
185
 
     *      name="longitude",
186
 
     *      in="formData",
187
 
     *      description="The longitude for this weather widget, only pass if useDisplayLocation set to 0",
188
 
     *      type="number",
189
 
     *      required=false
190
 
     *   ),
191
 
     *  @SWG\Parameter(
192
 
     *      name="latitude",
193
 
     *      in="formData",
194
 
     *      description="The latitude for this weather widget, only pass if useDisplayLocation set to 0",
195
 
     *      type="number",
196
 
     *      required=false
197
 
     *   ),
198
 
     *  @SWG\Parameter(
199
 
     *      name="templateId",
200
 
     *      in="formData",
201
 
     *      description="Use pre-configured templates, available options: weather-module0-5day, weather-module0-singleday, weather-module0-singleday2, weather-module1l, weather-module1p, weather-module2l, weather-module2p, weather-module3l, weather-module3p, weather-module4l, weather-module4p, weather-module5l, weather-module6v, weather-module6h",
202
 
     *      type="string",
203
 
     *      required=false
204
 
     *   ),
205
 
     *  @SWG\Parameter(
206
 
     *      name="units",
207
 
     *      in="formData",
208
 
     *      description="Units you would like to use, available options: auto, ca, si, uk2, us",
209
 
     *      type="string",
210
 
     *      required=false
211
 
     *   ),
212
 
     *  @SWG\Parameter(
213
 
     *      name="updateInterval",
214
 
     *      in="formData",
215
 
     *      description="Update interval in minutes, should be kept as high as possible, if data change once per hour, this should be set to 60",
216
 
     *      type="integer",
217
 
     *      required=false
218
 
     *   ),
219
 
     *  @SWG\Parameter(
220
 
     *      name="lang",
221
 
     *      in="formData",
222
 
     *      description="Language you'd like to use, supported languages ar, az, be, bs, cs, de, en, el, es, fr, hr, hu, id, it, is, kw, nb, nl, pl, pt, ru, sk, sr, sv, tet, tr, uk, x-pig-latin, zh, zh-tw",
223
 
     *      type="string",
224
 
     *      required=false
225
 
     *   ),
226
 
     *  @SWG\Parameter(
227
 
     *      name="dayConditionsOnly",
228
 
     *      in="formData",
229
 
     *      description="Flag (0, 1) Would you like to only show the Daytime weather conditions",
230
 
     *      type="integer",
231
 
     *      required=false
232
 
     *   ),
233
 
     *  @SWG\Parameter(
234
 
     *      name="overrideTemplate",
235
 
     *      in="formData",
236
 
     *      description="flag (0, 1) set to 0 and use templateId or set to 1 and provide whole template in the next parameters",
237
 
     *      type="integer",
238
 
     *      required=false
239
 
     *   ),
240
 
     *  @SWG\Parameter(
241
 
     *      name="widgetOriginalWidth",
242
 
     *      in="formData",
243
 
     *      description="This is the intended Width of the template and is used to scale the Widget within it's region when the template is applied, Pass only with overrideTemplate set to 1",
244
 
     *      type="integer",
245
 
     *      required=false
246
 
     *   ),
247
 
     *  @SWG\Parameter(
248
 
     *      name="widgetOriginalHeight",
249
 
     *      in="formData",
250
 
     *      description="This is the intended Height of the template and is used to scale the Widget within it's region when the template is applied, Pass only with overrideTemplate set to 1",
251
 
     *      type="integer",
252
 
     *      required=false
253
 
     *   ),
254
 
     *  @SWG\Parameter(
255
 
     *      name="currentTemplate",
256
 
     *      in="formData",
257
 
     *      description="Current template, Pass only with overrideTemplate set to 1 ",
258
 
     *      type="string",
259
 
     *      required=false
260
 
     *   ),
261
 
     *  @SWG\Parameter(
262
 
     *      name="dailyTemplate",
263
 
     *      in="formData",
264
 
     *      description="Replaces [dailyForecast] in main template, Pass only with overrideTemplate set to 1 ",
265
 
     *      type="string",
266
 
     *      required=false
267
 
     *   ),
268
 
     *  @SWG\Parameter(
269
 
     *      name="styleSheet",
270
 
     *      in="formData",
271
 
     *      description="Optional StyleSheet, Pass only with overrideTemplate set to 1 ",
272
 
     *      type="string",
273
 
     *      required=false
274
 
     *   ),
275
 
     *  @SWG\Parameter(
276
 
     *      name="styleSheet",
277
 
     *      in="formData",
278
 
     *      description="Optional JavaScript, Pass only with overrideTemplate set to 1 ",
279
 
     *      type="string",
280
 
     *      required=false
281
 
     *   ),
282
 
     *  @SWG\Response(
283
 
     *      response=201,
284
 
     *      description="successful operation",
285
 
     *      @SWG\Schema(ref="#/definitions/Widget"),
286
 
     *      @SWG\Header(
287
 
     *          header="Location",
288
 
     *          description="Location of the new widget",
289
 
     *          type="string"
290
 
     *      )
291
 
     *  )
292
 
     * )
 
148
     * Add Media to the Database
293
149
     */
294
150
    public function add()
295
151
    {
296
 
        $this->setDuration($this->getSanitizer()->getInt('duration', $this->getDuration()));
297
 
        $this->setUseDuration($this->getSanitizer()->getCheckbox('useDuration'));
298
 
        $this->setOption('name', $this->getSanitizer()->getString('name'));
299
 
        $this->setOption('useDisplayLocation', $this->getSanitizer()->getCheckbox('useDisplayLocation'));
300
 
        $this->setOption('longitude', $this->getSanitizer()->getDouble('longitude'));
301
 
        $this->setOption('latitude', $this->getSanitizer()->getDouble('latitude'));
302
 
        $this->setOption('templateId', $this->getSanitizer()->getString('templateId'));
303
 
        $this->setOption('overrideTemplate', $this->getSanitizer()->getCheckbox('overrideTemplate'));
304
 
        $this->setOption('units', $this->getSanitizer()->getString('units'));
305
 
        $this->setOption('updateInterval', $this->getSanitizer()->getInt('updateInterval', 60));
306
 
        $this->setOption('lang', $this->getSanitizer()->getString('lang'));
307
 
        $this->setOption('dayConditionsOnly', $this->getSanitizer()->getCheckbox('dayConditionsOnly'));
308
 
        
309
 
        if( $this->getOption('overrideTemplate') == 1 ){
310
 
            $this->setRawNode('styleSheet', $this->getSanitizer()->getParam('styleSheet', null));
311
 
            $this->setRawNode('currentTemplate', $this->getSanitizer()->getParam('currentTemplate', null));
312
 
            $this->setRawNode('dailyTemplate', $this->getSanitizer()->getParam('dailyTemplate', null));
313
 
            $this->setOption('widgetOriginalWidth', $this->getSanitizer()->getInt('widgetOriginalWidth'));
314
 
            $this->setOption('widgetOriginalHeight', $this->getSanitizer()->getInt('widgetOriginalHeight'));
315
 
        }
316
 
        
317
 
        $this->setRawNode('javaScript', $this->getSanitizer()->getParam('javaScript', ''));
318
 
        
 
152
        $this->setDuration(Sanitize::getInt('duration', $this->getDuration()));
 
153
        $this->setUseDuration(Sanitize::getCheckbox('useDuration'));
 
154
        $this->setOption('name', Sanitize::getString('name'));
 
155
        $this->setOption('useDisplayLocation', Sanitize::getCheckbox('useDisplayLocation'));
 
156
        $this->setOption('color', Sanitize::getString('color'));
 
157
        $this->setOption('longitude', Sanitize::getDouble('longitude'));
 
158
        $this->setOption('latitude', Sanitize::getDouble('latitude'));
 
159
        $this->setOption('templateId', Sanitize::getString('templateId'));
 
160
        $this->setOption('icons', Sanitize::getString('icons'));
 
161
        $this->setOption('overrideTemplate', Sanitize::getCheckbox('overrideTemplate'));
 
162
        $this->setOption('size', Sanitize::getInt('size'));
 
163
        $this->setOption('units', Sanitize::getString('units'));
 
164
        $this->setOption('updateInterval', Sanitize::getInt('updateInterval', 60));
 
165
        $this->setOption('lang', Sanitize::getString('lang'));
 
166
        $this->setOption('dayConditionsOnly', Sanitize::getCheckbox('dayConditionsOnly'));
 
167
 
 
168
        $this->setRawNode('styleSheet', Sanitize::getParam('styleSheet', null));
 
169
        $this->setRawNode('currentTemplate', Sanitize::getParam('currentTemplate', null));
 
170
        $this->setRawNode('dailyTemplate', Sanitize::getParam('dailyTemplate', null));
 
171
 
319
172
        // Save the widget
320
173
        $this->validate();
321
174
        $this->saveWidget();
326
179
     */
327
180
    public function edit()
328
181
    {
329
 
        $this->setDuration($this->getSanitizer()->getInt('duration', $this->getDuration()));
330
 
        $this->setUseDuration($this->getSanitizer()->getCheckbox('useDuration'));
331
 
        $this->setOption('name', $this->getSanitizer()->getString('name'));
332
 
        $this->setOption('useDisplayLocation', $this->getSanitizer()->getCheckbox('useDisplayLocation'));
333
 
        $this->setOption('longitude', $this->getSanitizer()->getDouble('longitude'));
334
 
        $this->setOption('latitude', $this->getSanitizer()->getDouble('latitude'));
335
 
        $this->setOption('templateId', $this->getSanitizer()->getString('templateId'));
336
 
        $this->setOption('overrideTemplate', $this->getSanitizer()->getCheckbox('overrideTemplate'));
337
 
        $this->setOption('units', $this->getSanitizer()->getString('units'));
338
 
        $this->setOption('updateInterval', $this->getSanitizer()->getInt('updateInterval', 60));
339
 
        $this->setOption('lang', $this->getSanitizer()->getString('lang'));
340
 
        $this->setOption('dayConditionsOnly', $this->getSanitizer()->getCheckbox('dayConditionsOnly'));
341
 
        
342
 
        if( $this->getOption('overrideTemplate') == 1 ){
343
 
            $this->setRawNode('styleSheet', $this->getSanitizer()->getParam('styleSheet', null));
344
 
            $this->setRawNode('currentTemplate', $this->getSanitizer()->getParam('currentTemplate', null));
345
 
            $this->setRawNode('dailyTemplate', $this->getSanitizer()->getParam('dailyTemplate', null));
346
 
            $this->setOption('widgetOriginalWidth', $this->getSanitizer()->getInt('widgetOriginalWidth'));
347
 
            $this->setOption('widgetOriginalHeight', $this->getSanitizer()->getInt('widgetOriginalHeight'));
348
 
        }
 
182
        $this->setDuration(Sanitize::getInt('duration', $this->getDuration()));
 
183
        $this->setUseDuration(Sanitize::getCheckbox('useDuration'));
 
184
        $this->setOption('name', Sanitize::getString('name'));
 
185
        $this->setOption('useDisplayLocation', Sanitize::getCheckbox('useDisplayLocation'));
 
186
        $this->setOption('color', Sanitize::getString('color'));
 
187
        $this->setOption('longitude', Sanitize::getDouble('longitude'));
 
188
        $this->setOption('latitude', Sanitize::getDouble('latitude'));
 
189
        $this->setOption('templateId', Sanitize::getString('templateId'));
 
190
        $this->setOption('icons', Sanitize::getString('icons'));
 
191
        $this->setOption('overrideTemplate', Sanitize::getCheckbox('overrideTemplate'));
 
192
        $this->setOption('size', Sanitize::getInt('size'));
 
193
        $this->setOption('units', Sanitize::getString('units'));
 
194
        $this->setOption('updateInterval', Sanitize::getInt('updateInterval', 60));
 
195
        $this->setOption('lang', Sanitize::getString('lang'));
 
196
        $this->setOption('dayConditionsOnly', Sanitize::getCheckbox('dayConditionsOnly'));
349
197
 
350
 
        $this->setRawNode('javaScript', $this->getSanitizer()->getParam('javaScript', ''));
 
198
        $this->setRawNode('styleSheet', Sanitize::getParam('styleSheet', null));
 
199
        $this->setRawNode('currentTemplate', Sanitize::getParam('currentTemplate', null));
 
200
        $this->setRawNode('dailyTemplate', Sanitize::getParam('dailyTemplate', null));
351
201
 
352
202
        // Save the widget
353
203
        $this->validate();
354
204
        $this->saveWidget();
355
205
    }
356
206
 
 
207
    public function iconsAvailable()
 
208
    {
 
209
        // Scan the forecast io folder for icons
 
210
        $icons = array();
 
211
 
 
212
        foreach (array_diff(scandir($this->resourceFolder), array('..', '.')) as $file) {
 
213
            if (stripos($file, '.png'))
 
214
                $icons[] = array('id' => $file, 'value' => ucfirst(str_replace('-', ' ', str_replace('.png', '', $file))));
 
215
        }
 
216
 
 
217
        return $icons;
 
218
    }
 
219
 
357
220
    /**
358
221
     * Units supported by Forecast.IO API
359
 
     * @return array The Units Available (temperature, wind speed and visible distance)
 
222
     * @return array The Units Available
360
223
     */
361
224
    public function unitsAvailable()
362
225
    {
363
226
        return array(
364
 
            array('id' => 'auto', 'value' => 'Automatically select based on geographic location', 'tempUnit' => '', 'windUnit' => '', 'visibilityUnit' => ''),
365
 
            array('id' => 'ca', 'value' => 'Canada', 'tempUnit' => 'C', 'windUnit' => 'KPH', 'visibilityUnit' => 'km'),
366
 
            array('id' => 'si', 'value' => 'Standard International Units', 'tempUnit' => 'C', 'windUnit' => 'MPS', 'visibilityUnit' => 'km'),
367
 
            array('id' => 'uk2', 'value' => 'United Kingdom', 'tempUnit' => 'C', 'windUnit' => 'MPH', 'visibilityUnit' => 'mi'),
368
 
            array('id' => 'us', 'value' => 'United States', 'tempUnit' => 'F', 'windUnit' => 'MPH', 'visibilityUnit' => 'km'),
 
227
            array('id' => 'auto', 'value' => 'Automatically select based on geographic location', 'tempUnit' => ''),
 
228
            array('id' => 'ca', 'value' => 'Canada', 'tempUnit' => 'F'),
 
229
            array('id' => 'si', 'value' => 'Standard International Units', 'tempUnit' => 'C'),
 
230
            array('id' => 'uk', 'value' => 'United Kingdom', 'tempUnit' => 'C'),
 
231
            array('id' => 'us', 'value' => 'United States', 'tempUnit' => 'F'),
369
232
        );
370
233
    }
371
234
 
376
239
    public function supportedLanguages()
377
240
    {
378
241
        return array(
379
 
            array('id' => 'ar', 'value' => __('Arabic')),
380
 
            array('id' => 'az', 'value' => __('Azerbaijani')),
381
 
            array('id' => 'be', 'value' => __('Belarusian')),
 
242
            array('id' => 'en', 'value' => __('English')),
382
243
            array('id' => 'bs', 'value' => __('Bosnian')),
383
 
            array('id' => 'bg', 'value' => __('Bulgarian')),
384
 
            array('id' => 'ca', 'value' => __('Catalan')),
385
 
            array('id' => 'kw', 'value' => __('Cornish')),
386
 
            array('id' => 'zh', 'value' => __('Simplified Chinese')),
387
 
            array('id' => 'zh-tw', 'value' => __('Traditional Chinese')),
388
 
            array('id' => 'hr', 'value' => __('Croatian')),
389
 
            array('id' => 'cs', 'value' => __('Czech')),
390
 
            array('id' => 'da', 'value' => __('Danish')),
391
 
            array('id' => 'nl', 'value' => __('Dutch')),
392
 
            array('id' => 'ka', 'value' => __('Georgian')),
393
244
            array('id' => 'de', 'value' => __('German')),
394
 
            array('id' => 'el', 'value' => __('Greek')),
395
 
            array('id' => 'en', 'value' => __('English')),
396
 
            array('id' => 'et', 'value' => __('Estonian')),
397
 
            array('id' => 'fi', 'value' => __('Finnish')),
 
245
            array('id' => 'es', 'value' => __('Spanish')),
398
246
            array('id' => 'fr', 'value' => __('French')),
399
 
            array('id' => 'hu', 'value' => __('Hungarian')),
400
 
            array('id' => 'is', 'value' => __('Icelandic')),
401
 
            array('id' => 'id', 'value' => __('Indonesian')),
402
247
            array('id' => 'it', 'value' => __('Italian')),
403
 
            array('id' => 'ja', 'value' => __('Japanese')),
404
 
            array('id' => 'nb', 'value' => __('Norwegian Bokmål')),
 
248
            array('id' => 'nl', 'value' => __('Dutch')),
405
249
            array('id' => 'pl', 'value' => __('Polish')),
406
250
            array('id' => 'pt', 'value' => __('Portuguese')),
407
251
            array('id' => 'ru', 'value' => __('Russian')),
408
 
            array('id' => 'sr', 'value' => __('Serbian')),
409
 
            array('id' => 'sk', 'value' => __('Slovak')),
410
 
            array('id' => 'sl', 'value' => __('Slovenian')),
411
 
            array('id' => 'es', 'value' => __('Spanish')),
412
 
            array('id' => 'sv', 'value' => __('Swedish')),
413
252
            array('id' => 'tet', 'value' => __('Tetum')),
414
253
            array('id' => 'tr', 'value' => __('Turkish')),
415
 
            array('id' => 'uk', 'value' => __('Ukrainian')),
416
254
            array('id' => 'x-pig-latin', 'value' => __('lgpay Atinlay'))
417
255
        );
418
256
    }
420
258
    /**
421
259
     * Get Tab
422
260
     */
423
 
     public function getTab($tab)
424
 
     {
425
 
         if ($tab == 'forecast') {
426
 
             if (!$data = $this->getForecastData(0))
427
 
                 throw new NotFoundException(__('No data returned, please check error log.'));
428
 
             $rows = array();
429
 
             foreach ($data['currently'] as $key => $value) {
430
 
                 if (stripos($key, 'time')) {
431
 
                     $value = $this->getDate()->getLocalDate($value);
432
 
                 }
433
 
                 $rows[] = array('forecast' => __('Current'), 'key' => $key, 'value' => $value);
434
 
             }
435
 
             foreach ($data['daily']['data'][0] as $key => $value) {
436
 
                 if (stripos($key, 'time')) {
437
 
                     $value = $this->getDate()->getLocalDate($value);
438
 
                 }
439
 
                 $rows[] = array('forecast' => __('Daily'), 'key' => $key, 'value' => $value);
440
 
             }
441
 
             return ['forecast' => $rows];
442
 
         } else if ($tab == 'exporttemplate') {
443
 
             return [
444
 
                 'template' => json_encode([
445
 
                     'id' => 'uniqueId',
446
 
                     'value' => 'title',
447
 
                     'designWidth' => $this->getOption('designWidth'),
448
 
                     'designHeight' => $this->getOption('designHeight'),
449
 
                     'main' => $this->getRawNode('currentTemplate'),
450
 
                     'daily' => $this->getRawNode('dailyTemplate'),
451
 
                     'css' => $this->getRawNode('styleSheet'),                     
452
 
                     'widgetOriginalWidth' => intval($this->getOption('widgetOriginalWidth')),
453
 
                     'widgetOriginalHeight' => intval($this->getOption('widgetOriginalHeight')),
454
 
                     'image' => 'preview-image'
455
 
                 ])
456
 
             ];
457
 
         } else {
458
 
             return [];
459
 
         }
460
 
     }
 
261
    public function getTab($tab)
 
262
    {
 
263
        if (!$data = $this->getForecastData(0))
 
264
            throw new NotFoundException(__('No data returned, please check error log.'));
 
265
 
 
266
        $rows = array();
 
267
        foreach ($data['currently'] as $key => $value) {
 
268
            if (stripos($key, 'time')) {
 
269
                $value = Date::getLocalDate($value);
 
270
            }
 
271
 
 
272
            $rows[] = array('forecast' => __('Current'), 'key' => $key, 'value' => $value);
 
273
        }
 
274
 
 
275
        foreach ($data['daily']['data'][0] as $key => $value) {
 
276
            if (stripos($key, 'time')) {
 
277
                $value = Date::getLocalDate($value);
 
278
            }
 
279
 
 
280
            $rows[] = array('forecast' => __('Daily'), 'key' => $key, 'value' => $value);
 
281
        }
 
282
 
 
283
        return ['forecast' => $rows];
 
284
    }
461
285
 
462
286
    /**
463
287
     * Get the forecast data for the provided display id
464
288
     * @param int $displayId
465
 
     * @return array|boolean
466
 
     * @throws XiboException
 
289
     * @return array
467
290
     */
468
291
    private function getForecastData($displayId)
469
292
    {
470
 
        $defaultLat = $this->getConfig()->GetSetting('DEFAULT_LAT');
471
 
        $defaultLong = $this->getConfig()->GetSetting('DEFAULT_LONG');
 
293
        $defaultLat = Config::getSetting('DEFAULT_LAT');
 
294
        $defaultLong = Config::getSetting('DEFAULT_LONG');
472
295
 
473
296
        if ($this->getOption('useDisplayLocation') == 1) {
474
297
            // Use the display ID or the default.
475
298
            if ($displayId != 0) {
476
299
 
477
 
                $display = $this->displayFactory->getById($displayId);
478
 
 
479
 
                if ($display->latitude != '' && $display->longitude != '' && v::latitude()->validate($display->latitude) && v::longitude()->validate($display->longitude)) {
480
 
                    $defaultLat = $display->latitude;
481
 
                    $defaultLong = $display->longitude;
482
 
                } else {
483
 
                    $this->getLog()->info('Warning, display %s does not have a lat/long or they are invalid, and yet a forecast widget is set to use display location.', $display->display);
484
 
                }
 
300
                $display = DisplayFactory::getById($displayId);
 
301
                $defaultLat = $display->latitude;
 
302
                $defaultLong = $display->longitude;
485
303
            }
486
304
        } else {
487
305
            $defaultLat = $this->getOption('latitude', $defaultLat);
488
306
            $defaultLong = $this->getOption('longitude', $defaultLong);
489
307
        }
490
308
 
491
 
        if (!v::longitude()->validate($defaultLong) || !v::latitude()->validate($defaultLat)) {
492
 
            $this->getLog()->error('Weather widget configured with incorrect lat/long. WidgetId is ' . $this->getWidgetId() . ', Lat is ' . $defaultLat . ', Lng is ' . $defaultLong);
493
 
            return false;
494
 
        }
495
 
 
496
309
        $apiKey = $this->getSetting('apiKey');
497
310
        if ($apiKey == '')
498
311
            die(__('Incorrectly configured module'));
499
312
 
500
313
        // Query the API and Dump the Results.
501
 
        $apiOptions = array('units' => $this->getOption('units', 'auto'), 'lang' => $this->getOption('lang', 'en'), 'exclude' => 'minutely,hourly');
502
 
 
503
 
        $cache = $this->getPool()->getItem($this->makeCacheKey(md5($defaultLat . $defaultLong . implode('.', $apiOptions))));
504
 
        $data = $cache->get();
505
 
 
506
 
        if ($cache->isMiss()) {
507
 
            $cache->lock();
508
 
 
509
 
            $this->getLog()->notice('Getting Forecast from the API');
 
314
        $apiOptions = array('units' => $this->getOption('units', 'auto'), 'lang' => $this->getOption('lang', 'en'), 'exclude' => 'flags,minutely,hourly');
 
315
        $key = md5($defaultLat . $defaultLong . 'null' . implode('.', $apiOptions));
 
316
 
 
317
        if (!Cache::has($key)) {
 
318
            Log::notice('Getting Forecast from the API', $this->getModuleType(), __FUNCTION__);
510
319
            if (!$data = $this->get($defaultLat, $defaultLong, null, $apiOptions)) {
511
320
                return false;
512
321
            }
513
322
 
 
323
            // If the response is empty, cache it for less time
 
324
            $cacheDuration = $this->getSetting('cachePeriod');
 
325
 
514
326
            // Cache
515
 
            $cache->set($data);
516
 
            $cache->expiresAfter($this->getSetting('cachePeriod', 14400));
517
 
            $this->getPool()->saveDeferred($cache);
 
327
            Cache::put($key, $data, $cacheDuration);
518
328
        } else {
519
 
            $this->getLog()->debug('Getting Forecast from cache');
 
329
            Log::notice('Getting Forecast from the Cache with key: ' . $key, $this->getModuleType(), __FUNCTION__);
 
330
            $data = Cache::get($key);
520
331
        }
521
332
 
 
333
        //Debug::Audit('Data: ' . var_export($data, true));
 
334
 
522
335
        // Icon Mappings
523
336
        $icons = array(
524
337
            'unmapped' => 'wi-alien',
534
347
            'partly-cloudy-night' => 'wi-night-partly-cloudy',
535
348
        );
536
349
 
537
 
        // Temperature and wind Speed Unit Mappings
 
350
        // Temperature Unit Mappings
538
351
        $temperatureUnit = '';
539
 
        $windSpeedUnit = '';
540
 
        $visibilityDistanceUnit = '';
541
352
        foreach ($this->unitsAvailable() as $unit) {
542
 
            if ($unit['id'] == $data->flags->units) {
 
353
            if ($unit['id'] == $this->getOption('units', 'auto')) {
543
354
                $temperatureUnit = $unit['tempUnit'];
544
 
                $windSpeedUnit = $unit['windUnit'];
545
 
                $visibilityDistanceUnit = $unit['visibilityUnit'];
546
355
                break;
547
356
            }
548
357
        }
552
361
            if ($data->currently->icon == 'partly-cloudy-night')
553
362
                $data->currently->icon = 'clear-day';
554
363
        }
555
 
        
556
 
        // Wind Direction Mappings
557
 
        $cardinalDirections = array(
558
 
          'N' => array(337.5, 22.5),
559
 
          'NE' => array(22.5, 67.5),
560
 
          'E' => array(67.5, 112.5),
561
 
          'SE' => array(112.5, 157.5),
562
 
          'S' => array(157.5, 202.5),
563
 
          'SW' => array(202.5, 247.5),
564
 
          'W' => array(247.5, 292.5),
565
 
          'NW' => array(292.5, 337.5)
566
 
        );
567
 
        
568
 
        $windDirection = '';
569
 
        foreach ($cardinalDirections as $dir => $angles) {
570
 
          if ($data->currently->windBearing >= $angles[0] && $data->currently->windBearing < $angles[1]) {
571
 
            $windDirection = $dir;
572
 
            break;
573
 
          }
574
 
        }
575
364
 
576
365
        $data->currently->wicon = (isset($icons[$data->currently->icon]) ? $icons[$data->currently->icon] : $icons['unmapped']);
577
366
        $data->currently->temperatureFloor = (isset($data->currently->temperature) ? floor($data->currently->temperature) : '--');
578
 
        $data->currently->apparentTemperatureFloor = (isset($data->currently->apparentTemperature) ? floor($data->currently->apparentTemperature) : '--');
579
 
        $data->currently->temperatureRound = (isset($data->currently->temperature) ? round($data->currently->temperature, 0) : '--');
580
 
        $data->currently->apparentTemperatureRound = (isset($data->currently->apparentTemperature) ? round($data->currently->apparentTemperature, 0) : '--');
581
367
        $data->currently->summary = (isset($data->currently->summary) ? $data->currently->summary : '--');
582
368
        $data->currently->weekSummary = (isset($data->daily->summary) ? $data->daily->summary : '--');
583
369
        $data->currently->temperatureUnit = $temperatureUnit;
584
 
        $data->currently->windSpeedUnit = $windSpeedUnit;
585
 
        $data->currently->windDirection = $windDirection;
586
 
        $data->currently->visibilityDistanceUnit = $visibilityDistanceUnit;
587
 
        $data->currently->humidityPercent = (isset($data->currently->humidity)) ? ($data->currently->humidity * 100) : '--';
588
370
 
589
371
        // Convert a stdObject to an array
590
372
        $data = json_decode(json_encode($data), true);
591
373
 
592
 
        //Today Daily values
593
 
        $data['currently']['temperatureMaxFloor'] = (isset($data['daily']['data'][0]['temperatureMax'])) ? floor($data['daily']['data'][0]['temperatureMax']) : '--';
594
 
        $data['currently']['temperatureMinFloor'] = (isset($data['daily']['data'][0]['temperatureMin'])) ? floor($data['daily']['data'][0]['temperatureMin']) : '--';
595
 
        $data['currently']['temperatureMeanFloor'] = ($data['currently']['temperatureMaxFloor'] != '--' && $data['currently']['temperatureMinFloor'] != '--') ? floor((($data['currently']['temperatureMinFloor'] + $data['currently']['temperatureMaxFloor']) / 2)) : '--';
596
 
      
597
 
        $data['currently']['temperatureMaxRound'] = (isset($data['daily']['data'][0]['temperatureMax'])) ? round($data['daily']['data'][0]['temperatureMax'], 0) : '--';
598
 
        $data['currently']['temperatureMinRound'] = (isset($data['daily']['data'][0]['temperatureMin'])) ? round($data['daily']['data'][0]['temperatureMin'], 0) : '--';
599
 
        $data['currently']['temperatureMeanRound'] = ($data['currently']['temperatureMaxRound'] != '--' && $data['currently']['temperatureMinRound'] != '--') ? round((($data['currently']['temperatureMinRound'] + $data['currently']['temperatureMaxRound']) / 2), 0) : '--';
600
 
 
601
374
        // Process the icon for each day
602
375
        for ($i = 0; $i < 7; $i++) {
603
376
            // Are we set to only show daytime weather conditions?
605
378
                if ($data['daily']['data'][$i]['icon'] == 'partly-cloudy-night')
606
379
                    $data['daily']['data'][$i]['icon'] = 'clear-day';
607
380
            }
608
 
            
609
 
            // Wind Direction bearing to code
610
 
            $windDirectionDaily = '';
611
 
            foreach ($cardinalDirections as $dir => $angles) {
612
 
              if ($data['daily']['data'][$i]['windBearing'] >= $angles[0] && $data['daily']['data'][$i]['windBearing'] < $angles[1]) {
613
 
                $windDirectionDaily = $dir;
614
 
                break;
615
 
              }
616
 
            }
617
381
 
618
382
            $data['daily']['data'][$i]['wicon'] = (isset($icons[$data['daily']['data'][$i]['icon']]) ? $icons[$data['daily']['data'][$i]['icon']] : $icons['unmapped']);
619
383
            $data['daily']['data'][$i]['temperatureMaxFloor'] = (isset($data['daily']['data'][$i]['temperatureMax'])) ? floor($data['daily']['data'][$i]['temperatureMax']) : '--';
620
384
            $data['daily']['data'][$i]['temperatureMinFloor'] = (isset($data['daily']['data'][$i]['temperatureMin'])) ? floor($data['daily']['data'][$i]['temperatureMin']) : '--';
621
385
            $data['daily']['data'][$i]['temperatureFloor'] = ($data['daily']['data'][$i]['temperatureMinFloor'] != '--' && $data['daily']['data'][$i]['temperatureMaxFloor'] != '--') ? floor((($data['daily']['data'][$i]['temperatureMinFloor'] + $data['daily']['data'][$i]['temperatureMaxFloor']) / 2)) : '--';
622
 
            $data['daily']['data'][$i]['temperatureMaxRound'] = (isset($data['daily']['data'][$i]['temperatureMax'])) ? round($data['daily']['data'][$i]['temperatureMax'], 0) : '--';
623
 
            $data['daily']['data'][$i]['temperatureMinRound'] = (isset($data['daily']['data'][$i]['temperatureMin'])) ? round($data['daily']['data'][$i]['temperatureMin'], 0) : '--';
624
 
            $data['daily']['data'][$i]['temperatureRound'] = ($data['daily']['data'][$i]['temperatureMinRound'] != '--' && $data['daily']['data'][$i]['temperatureMaxRound'] != '--') ? round((($data['daily']['data'][$i]['temperatureMinRound'] + $data['daily']['data'][$i]['temperatureMaxRound']) / 2), 0) : '--';
625
386
            $data['daily']['data'][$i]['temperatureUnit'] = $temperatureUnit;
626
 
            $data['daily']['data'][$i]['windSpeedUnit'] = $windSpeedUnit;
627
 
            $data['daily']['data'][$i]['visibilityDistanceUnit'] = $visibilityDistanceUnit;
628
 
            $data['daily']['data'][$i]['humidityPercent'] = (isset($data['daily']['data'][$i]['humidity'])) ? ($data['daily']['data'][$i]['humidity'] * 100) : '--';
629
 
            $data['daily']['data'][$i]['windDirection'] = $windDirectionDaily;
630
387
        }
631
388
 
632
389
        return $data;
633
390
    }
634
391
 
635
 
    private function makeSubstitutions($data, $source, $timezone = NULL)
 
392
    private function makeSubstitutions($data, $source)
636
393
    {
637
394
        // Replace all matches.
638
395
        $matches = '';
646
403
            if (stripos($replace, 'time|') > -1) {
647
404
                $timeSplit = explode('|', $replace);
648
405
 
649
 
                $this->getLog()->debug('Time Substitution for source time ' . $data['time'] . ' and timezone ' . $timezone . ', format ' . $timeSplit[1]);
650
 
 
651
 
                $time = $this->getDate()->getLocalDate($data['time'], $timeSplit[1], $timezone);
652
 
 
653
 
                $this->getLog()->debug('Time Substitution: ' . (string)($time));
 
406
                $time = Date::getLocalDate($data['time'], $timeSplit[1]);
 
407
 
 
408
                Log::info('Time: ' . $time);
654
409
 
655
410
                // Pull time out of the array
656
411
                $source = str_replace($sub, $time, $source);
668
423
     * Get Resource
669
424
     * @param int $displayId
670
425
     * @return mixed
671
 
     * @throws XiboException
672
426
     */
673
427
    public function getResource($displayId = 0)
674
428
    {
678
432
 
679
433
        // Do we need to override the language?
680
434
        // TODO: I don't like this date fix, the library should really check the file exists?
681
 
        $lang = $this->getOption('lang', 'en');
682
 
        if ($lang != 'en' && file_exists(PROJECT_ROOT . '/vendor/jenssegers/date/src/Lang/' . $lang . '.php')) {
683
 
            mb_internal_encoding('UTF-8');
684
 
            $this->getLog()->debug('Setting language to: ' . $lang);
685
 
            $this->getDate()->setLocale($lang);
 
435
        if ($this->getOption('lang', 'en') != 'en' && file_exists(PROJECT_ROOT . '/vendor/jenssegers/date/src/Lang/' . $this->getOption('lang') . '.php')) {
 
436
            \Jenssegers\Date\Date::setLocale($this->getOption('lang'));
686
437
        }
687
438
 
688
439
        $data = [];
689
 
        $isPreview = ($this->getSanitizer()->getCheckbox('preview') == 1);
 
440
        $isPreview = (Sanitize::getCheckbox('preview') == 1);
690
441
 
691
442
        // Replace the View Port Width?
692
443
        $data['viewPortWidth'] = ($isPreview) ? $this->region->width : '[[ViewPortWidth]]';
693
 
        
694
 
        if( $this->getOption('overrideTemplate') == 0 ) {
695
 
            
696
 
            // Get CSS and HTML from the default templates
697
 
 
698
 
            $template = $this->getTemplateById($this->getOption('templateId'));
699
 
            
700
 
            if (isset($template)) {
701
 
                $body = $template['main'];
702
 
                $dailyTemplate = $template['daily'];
703
 
                $styleSheet = $template['css'];
704
 
                $widgetOriginalWidth = $template['widgetOriginalWidth'];
705
 
                $widgetOriginalHeight = $template['widgetOriginalHeight'];
706
 
            }
707
 
            
708
 
        } else {
709
 
            // Get CSS and HTML from the override input fields
710
 
            
711
 
            $body = $this->parseLibraryReferences($isPreview, $this->getRawNode('currentTemplate', ''));
712
 
            $dailyTemplate = $this->parseLibraryReferences($isPreview, $this->getRawNode('dailyTemplate', ''));
713
 
            $styleSheet = $this->getRawNode('styleSheet', '');
714
 
            $widgetOriginalWidth = $this->getSanitizer()->int($this->getOption('widgetOriginalWidth'));
715
 
            $widgetOriginalHeight = $this->getSanitizer()->int($this->getOption('widgetOriginalHeight'));
716
 
        }
717
 
        
718
 
        // Parse library references
719
 
        $body = $this->parseLibraryReferences($isPreview, $body);
720
 
        $dailyTemplate = $this->parseLibraryReferences($isPreview, $dailyTemplate);
721
 
        
722
 
        // Provide the background images to the templates styleSheet
723
 
        $styleSheet = $this->makeSubstitutions([
724
 
            'cloudy-image' => $this->getResourceUrl('forecastio/wi-cloudy.jpg'),
725
 
            'day-cloudy-image' => $this->getResourceUrl('forecastio/wi-day-cloudy.jpg'),
726
 
            'day-sunny-image' => $this->getResourceUrl('forecastio/wi-day-sunny.jpg'),
727
 
            'fog-image' => $this->getResourceUrl('forecastio/wi-fog.jpg'),
728
 
            'hail-image' => $this->getResourceUrl('forecastio/wi-hail.jpg'),
729
 
            'night-clear-image' => $this->getResourceUrl('forecastio/wi-night-clear.jpg'),
730
 
            'night-partly-cloudy-image' => $this->getResourceUrl('forecastio/wi-night-partly-cloudy.jpg'),            
731
 
            'rain-image' => $this->getResourceUrl('forecastio/wi-rain.jpg'),
732
 
            'snow-image' => $this->getResourceUrl('forecastio/wi-snow.jpg'),
733
 
            'windy-image' => $this->getResourceUrl('forecastio/wi-windy.jpg'),
734
 
          ], $styleSheet
735
 
        );
736
444
 
737
445
        $headContent = '
738
 
            <link href="' . $this->getResourceUrl('vendor/bootstrap.min.css')  . '" rel="stylesheet" media="screen">
739
446
            <link href="' . $this->getResourceUrl('forecastio/weather-icons.min.css') . '" rel="stylesheet" media="screen">
740
 
            <link href="' . $this->getResourceUrl('forecastio/font-awesome.min.css')  . '" rel="stylesheet" media="screen">
741
 
            <link href="' . $this->getResourceUrl('forecastio/animate.css')  . '" rel="stylesheet" media="screen">
742
 
            <style type="text/css"> body { background-color: transparent }</style>
743
447
            <style type="text/css">
744
 
                ' . $this->parseLibraryReferences($isPreview, $styleSheet) . '
 
448
                .container { color: ' . $this->getOption('color', '000') . '; }
 
449
                #content { zoom: ' . $this->getOption('size', 1) . '; }
 
450
                ' . $this->parseLibraryReferences($isPreview, $this->getRawNode('styleSheet', null)) . '
745
451
            </style>
746
452
        ';
747
453
 
748
454
        // Add our fonts.css file
749
 
        $headContent .= '<link href="' . (($isPreview) ? $this->getApp()->urlFor('library.font.css') : 'fonts.css') . '" rel="stylesheet" media="screen">';
750
 
        $headContent .= '<style type="text/css">' . file_get_contents($this->getConfig()->uri('css/client.css', true)) . '</style>';
 
455
        $headContent .= '<link href="' . $this->getResourceUrl('fonts.css') . '" rel="stylesheet" media="screen">';
 
456
        $headContent .= '<style type="text/css">' . file_get_contents(Theme::uri('css/client.css', true)) . '</style>';
751
457
 
752
458
        // Replace any icon sets
753
459
        $data['head'] = str_replace('[[ICONS]]', $this->getResourceUrl('forecastio/' . $this->getOption('icons')), $headContent);
754
460
 
755
 
        // Get the JavaScript node
756
 
        $javaScript = $this->parseLibraryReferences($isPreview, $this->getRawNode('javaScript', ''));
 
461
        // Make some body content
 
462
        $body = $this->parseLibraryReferences($isPreview, $this->getRawNode('currentTemplate', null));
 
463
        $dailyTemplate = $this->parseLibraryReferences($isPreview, $this->getRawNode('dailyTemplate', null));
757
464
 
758
465
        // Handle the daily template (if its here)
759
 
        $dailySubs = '';
760
 
        $matches = '';
761
 
        preg_match_all('/\[dailyForecast.*?\]/', $body, $matches);
762
 
        // Substitute
763
 
        foreach ($matches[0] as $sub) {
764
 
            $replace = str_replace('[', '', str_replace(']', '', $sub));
765
 
            // Handling for date/time
766
 
            $itterations = 7;
767
 
            $stopPosition = $itterations;
768
 
            $offset = 0;
769
 
            if (stripos($replace, '|') > -1) {
770
 
                $quantity = explode('|', $replace);
771
 
                $itterations = $quantity[1];
772
 
                
773
 
                if (count($quantity) > 1)
774
 
                  $offset = $quantity[2];
775
 
 
776
 
                  $stopPosition = (($itterations+$offset) > 7) ? 7 : $itterations+$offset;
777
 
            
778
 
            }
779
 
 
 
466
        if (stripos($body, '[dailyForecast]')) {
780
467
            // Pull it out, and run substitute over it for each day
 
468
            $dailySubs = '';
781
469
            // Substitute for every day (i.e. 7 times).
782
 
            for ($i = $offset; $i < $stopPosition; $i++) {
783
 
                $this->getLog()->debug('Substitiution for Daily, day ' . $i);
784
 
                $dailySubs .= $this->makeSubstitutions($foreCast['daily']['data'][$i], $dailyTemplate, $foreCast['timezone']);
 
470
            for ($i = 0; $i < 7; $i++) {
 
471
                $dailySubs .= $this->makeSubstitutions($foreCast['daily']['data'][$i], $dailyTemplate);
785
472
            }
 
473
 
786
474
            // Substitute the completed template
787
 
            $body = str_replace($sub, $dailySubs, $body);
 
475
            $body = str_replace('[dailyForecast]', $dailySubs, $body);
788
476
        }
789
477
 
790
 
 
791
478
        // Run replace over the main template
792
 
        $data['body'] = $this->makeSubstitutions($foreCast['currently'], $body, $foreCast['timezone']);
 
479
        $data['body'] = $this->makeSubstitutions($foreCast['currently'], $body);
 
480
 
793
481
 
794
482
        // JavaScript to control the size (override the original width and height so that the widget gets blown up )
795
483
        $options = array(
796
 
            'previewWidth' => $this->getSanitizer()->getDouble('width', 0),
797
 
            'previewHeight' => $this->getSanitizer()->getDouble('height', 0),
 
484
            'previewWidth' => Sanitize::getDouble('width', 0),
 
485
            'previewHeight' => Sanitize::getDouble('height', 0),
798
486
            'originalWidth' => $this->region->width,
799
487
            'originalHeight' => $this->region->height,
800
 
            'scaleOverride' => $this->getSanitizer()->getDouble('scale_override', 0),
801
 
            'widgetDesignWidth' => $widgetOriginalWidth,
802
 
            'widgetDesignHeight'=> $widgetOriginalHeight
 
488
            'scaleOverride' => Sanitize::getDouble('scale_override', 0)
803
489
        );
804
490
 
805
491
        $javaScriptContent = '<script type="text/javascript" src="' . $this->getResourceUrl('vendor/jquery-1.11.1.min.js') . '"></script>';
806
492
        $javaScriptContent .= '<script type="text/javascript" src="' . $this->getResourceUrl('xibo-layout-scaler.js') . '"></script>';
807
 
        $javaScriptContent .= '<script type="text/javascript" src="' . $this->getResourceUrl('xibo-image-render.js') . '"></script>';
808
493
        $javaScriptContent .= '<script>
809
494
 
810
495
            var options = ' . json_encode($options) . '
811
496
 
812
497
            $(document).ready(function() {
813
498
                $("body").xiboLayoutScaler(options);
814
 
                $("#content").find("img").xiboImageRender(options);
815
499
            });
816
500
        </script>';
817
 
        $javaScriptContent .= $javaScript;
818
501
 
819
502
        // Replace the After body Content
820
503
        $data['javaScript'] = $javaScriptContent;
821
504
 
822
505
        // Update and save widget if we've changed our assignments.
823
506
        if ($this->hasMediaChanged())
824
 
            $this->widget->save(['saveWidgetOptions' => false, 'notify' => false, 'notifyDisplays' => true, 'audit' => false]);
 
507
            $this->widget->save(['saveWidgetOptions' => false]);
825
508
 
826
509
        // Return that content.
827
510
        return $this->renderTemplate($data);
850
533
            $request_url .= '?'. http_build_query($options);
851
534
        }
852
535
 
853
 
        $this->getLog()->debug('Calling API with: ' . $request_url);
 
536
        Log::debug('Calling API with: ' . $request_url);
854
537
 
855
538
        $request_url = str_replace('[APIKEY]', $this->getSetting('apiKey'), $request_url);
856
539
 
858
541
        $client = new Client();
859
542
 
860
543
        try {
861
 
            $response = $client->get($request_url, $this->getConfig()->getGuzzleProxy(['connect_timeout' => 20]));
 
544
            $response = $client->get($request_url, Config::getGuzzleProxy(['connect_timeout' => 20]));
862
545
 
863
546
            // Success?
864
547
            if ($response->getStatusCode() != 200) {
865
 
                $this->getLog()->error('ForecastIO API returned %d status. Unable to proceed. Headers = %s', $response->getStatusCode(), var_export($response->getHeaders(), true));
 
548
                Log::error('ForecastIO API returned %d status. Unable to proceed. Headers = %s', $response->getStatusCode(), var_export($response->getHeaders(), true));
866
549
 
867
550
                // See if we can parse the error.
868
551
                $body = json_decode($response->getBody());
869
552
 
870
 
                $this->getLog()->error('ForecastIO Error: ' . ((isset($body->errors[0])) ? $body->errors[0]->message : 'Unknown Error'));
 
553
                Log::error('ForecastIO Error: ' . ((isset($body->errors[0])) ? $body->errors[0]->message : 'Unknown Error'));
871
554
 
872
555
                return false;
873
556
            }
878
561
            return $body;
879
562
        }
880
563
        catch (RequestException $e) {
881
 
            $this->getLog()->error('Unable to reach Forecast API: %s', $e->getMessage());
 
564
            Log::error('Unable to reach Forecast API: %s', $e->getMessage());
882
565
            return false;
883
566
        }
884
567
    }