Skip to content

Commit 1486c97

Browse files
committed
Fix Slides links
1 parent 143d3a7 commit 1486c97

File tree

2 files changed

+184
-0
lines changed

2 files changed

+184
-0
lines changed

src/UI/Lessons.php

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -372,6 +372,27 @@ public static function absolute_url_ref(&$url) {
372372
*/
373373
public static function expandLink($url) {
374374
global $CFG;
375+
// Skip expansion if URL already starts with http:// or https://
376+
if (strpos($url, 'http://') === 0 || strpos($url, 'https://') === 0) {
377+
return $url;
378+
}
379+
380+
// Clean up duplicate placeholders first (e.g., {apphome}/{apphome} -> {apphome})
381+
$url = preg_replace('#\{apphome\}/+\{apphome\}#', '{apphome}', $url);
382+
$url = preg_replace('#\{wwwroot\}/+\{wwwroot\}#', '{wwwroot}', $url);
383+
384+
// Check if URL already contains expanded apphome or wwwroot (prevent double expansion)
385+
$has_expanded_apphome = isset($CFG->apphome) && strpos($url, $CFG->apphome) !== false;
386+
$has_expanded_wwwroot = isset($CFG->wwwroot) && strpos($url, $CFG->wwwroot) !== false;
387+
388+
if ($has_expanded_apphome || $has_expanded_wwwroot) {
389+
// URL already contains expanded values, just remove any remaining placeholders
390+
$url = str_replace(array('{apphome}', '{wwwroot}'), '', $url);
391+
// Clean up any double slashes that might result
392+
$url = preg_replace('#([^:])//+#', '$1/', $url);
393+
return $url;
394+
}
395+
375396
$search = array(
376397
"{apphome}",
377398
"{wwwroot}",

tests/UI/LessonsTest.php

Lines changed: 163 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,26 @@
11
<?php
22

33
require_once "src/UI/Lessons.php";
4+
require_once "src/Config/ConfigInfo.php";
45

56
use \Tsugi\UI\Lessons;
67

78
class LessonsTest extends \PHPUnit\Framework\TestCase
89
{
910
private $testJsonFile;
11+
private $originalCFG;
1012

1113
protected function setUp(): void
1214
{
1315
parent::setUp();
16+
global $CFG;
17+
$this->originalCFG = $CFG;
18+
19+
// Set up test CFG
20+
$CFG = new \Tsugi\Config\ConfigInfo(basename(__FILE__), 'http://localhost');
21+
$CFG->apphome = 'http://localhost/app';
22+
$CFG->wwwroot = 'http://localhost';
23+
1424
// Create a temporary JSON file for testing
1525
$this->testJsonFile = sys_get_temp_dir() . '/test_lessons_' . uniqid() . '.json';
1626
$testData = [
@@ -34,10 +44,13 @@ protected function setUp(): void
3444

3545
protected function tearDown(): void
3646
{
47+
global $CFG;
3748
// Clean up temporary file
3849
if (file_exists($this->testJsonFile)) {
3950
unlink($this->testJsonFile);
4051
}
52+
// Restore original CFG
53+
$CFG = $this->originalCFG;
4154
parent::tearDown();
4255
}
4356

@@ -86,5 +99,155 @@ public function testGetSettingFromLoadedJson() {
8699
$result = $lessons->getSetting('nonexistent', 'default');
87100
$this->assertEquals('default', $result, 'getSetting should return default for nonexistent key');
88101
}
102+
103+
/**
104+
* Test expandLink() static method - does macro substitution on URLs
105+
*/
106+
public function testExpandLink() {
107+
global $CFG;
108+
109+
// Test with {apphome} macro
110+
$url = '{apphome}/some/path';
111+
$result = Lessons::expandLink($url);
112+
$this->assertEquals('http://localhost/app/some/path', $result, 'expandLink should replace {apphome}');
113+
114+
// Test with {wwwroot} macro
115+
$url = '{wwwroot}/other/path';
116+
$result = Lessons::expandLink($url);
117+
$this->assertEquals('http://localhost/other/path', $result, 'expandLink should replace {wwwroot}');
118+
119+
// Test with both macros
120+
$url = '{apphome}/app and {wwwroot}/www';
121+
$result = Lessons::expandLink($url);
122+
$this->assertEquals('http://localhost/app/app and http://localhost/www', $result, 'expandLink should replace both macros');
123+
124+
// Test with no macros
125+
$url = 'http://example.com/path';
126+
$result = Lessons::expandLink($url);
127+
$this->assertEquals('http://example.com/path', $result, 'expandLink should leave URLs without macros unchanged');
128+
}
129+
130+
/**
131+
* Test expandLink() with URLs that already start with http:// or https://
132+
*/
133+
public function testExpandLinkSkipsHttpUrls() {
134+
global $CFG;
135+
136+
// Test with http:// URL (should skip expansion)
137+
$url = 'http://example.com/path';
138+
$result = Lessons::expandLink($url);
139+
$this->assertEquals('http://example.com/path', $result, 'expandLink should skip URLs starting with http://');
140+
141+
// Test with https:// URL (should skip expansion)
142+
$url = 'https://example.com/path';
143+
$result = Lessons::expandLink($url);
144+
$this->assertEquals('https://example.com/path', $result, 'expandLink should skip URLs starting with https://');
145+
146+
// Test with http:// URL containing macros (should still skip)
147+
$url = 'http://example.com/{apphome}/path';
148+
$result = Lessons::expandLink($url);
149+
$this->assertEquals('http://example.com/{apphome}/path', $result, 'expandLink should skip URLs starting with http:// even if they contain macros');
150+
}
151+
152+
/**
153+
* Test expandLink() with duplicate placeholders cleanup
154+
*/
155+
public function testExpandLinkCleansDuplicatePlaceholders() {
156+
global $CFG;
157+
158+
// Test with duplicate {apphome} placeholders
159+
$url = '{apphome}/{apphome}/path';
160+
$result = Lessons::expandLink($url);
161+
$this->assertEquals('http://localhost/app/path', $result, 'expandLink should clean up duplicate {apphome} placeholders');
162+
163+
// Test with duplicate {wwwroot} placeholders
164+
$url = '{wwwroot}/{wwwroot}/path';
165+
$result = Lessons::expandLink($url);
166+
$this->assertEquals('http://localhost/path', $result, 'expandLink should clean up duplicate {wwwroot} placeholders');
167+
168+
// Test with multiple slashes between duplicates
169+
$url = '{apphome}//{apphome}/path';
170+
$result = Lessons::expandLink($url);
171+
$this->assertEquals('http://localhost/app/path', $result, 'expandLink should clean up duplicate placeholders with multiple slashes');
172+
}
173+
174+
/**
175+
* Test expandLink() prevents double expansion
176+
*/
177+
public function testExpandLinkPreventsDoubleExpansion() {
178+
global $CFG;
179+
180+
// Test that URLs starting with http:// are returned as-is (even with placeholders)
181+
$url = 'http://localhost/app/some/path/{apphome}';
182+
$result = Lessons::expandLink($url);
183+
$this->assertEquals('http://localhost/app/some/path/{apphome}', $result, 'expandLink should return http:// URLs as-is without processing');
184+
185+
// Test double expansion prevention with a URL that contains full expanded apphome
186+
// but doesn't start with http:// (edge case - unlikely in practice)
187+
$url = 'someprefix' . $CFG->apphome . '/path/{apphome}';
188+
$result = Lessons::expandLink($url);
189+
// Should detect that apphome is already present and remove placeholder
190+
$this->assertStringNotContainsString('{apphome}', $result, 'expandLink should remove placeholders when URL already contains full expanded apphome');
191+
$this->assertStringContainsString($CFG->apphome, $result, 'expandLink should preserve existing expanded apphome');
192+
193+
// Test with wwwroot
194+
$url = 'someprefix' . $CFG->wwwroot . '/path/{wwwroot}';
195+
$result = Lessons::expandLink($url);
196+
$this->assertStringNotContainsString('{wwwroot}', $result, 'expandLink should remove placeholders when URL already contains full expanded wwwroot');
197+
}
198+
199+
/**
200+
* Test expandLink() cleans up double slashes
201+
*/
202+
public function testExpandLinkCleansDoubleSlashes() {
203+
global $CFG;
204+
205+
// Test that double slashes are cleaned up after placeholder removal
206+
$url = 'prefix' . $CFG->apphome . '/path//{apphome}';
207+
$result = Lessons::expandLink($url);
208+
// After removing placeholder, should clean up double slashes
209+
$pos = strpos($result, $CFG->apphome);
210+
if ($pos !== false) {
211+
$after_apphome = substr($result, $pos + strlen($CFG->apphome));
212+
// Should not have double slashes (except http:// at the start)
213+
$this->assertStringNotContainsString('//', $after_apphome, 'expandLink should clean up double slashes after placeholder removal');
214+
}
215+
216+
// Test normal expansion doesn't create double slashes
217+
$url = '{apphome}/path';
218+
$result = Lessons::expandLink($url);
219+
$this->assertEquals($CFG->apphome . '/path', $result, 'Normal expansion should create clean URLs');
220+
}
221+
222+
/**
223+
* Test isSingle() method
224+
*/
225+
public function testIsSingle() {
226+
$lessons = new class extends Lessons {
227+
public function __construct() {
228+
// Skip parent constructor
229+
}
230+
};
231+
232+
// Test with no anchor or position
233+
$lessons->anchor = null;
234+
$lessons->position = null;
235+
$this->assertFalse($lessons->isSingle(), 'isSingle should return false when anchor and position are null');
236+
237+
// Test with anchor set
238+
$lessons->anchor = 'test-anchor';
239+
$lessons->position = null;
240+
$this->assertTrue($lessons->isSingle(), 'isSingle should return true when anchor is set');
241+
242+
// Test with position set
243+
$lessons->anchor = null;
244+
$lessons->position = 5;
245+
$this->assertTrue($lessons->isSingle(), 'isSingle should return true when position is set');
246+
247+
// Test with both set
248+
$lessons->anchor = 'test-anchor';
249+
$lessons->position = 5;
250+
$this->assertTrue($lessons->isSingle(), 'isSingle should return true when both anchor and position are set');
251+
}
89252

90253
}

0 commit comments

Comments
 (0)