Skip to content

Commit

Permalink
[Backport release_3_9] Js files finder (#5051)
Browse files Browse the repository at this point in the history
* UserFileFinder class

* update controller to use UserFileFinder class

* add 'param' methode parameter for AppContext Interface and JelixContext

* ContextForText simply return url

* unit tests, add js files in default/repo/subfolder

---------

Co-authored-by: Raphaël Martin <[email protected]>
  • Loading branch information
3liz-bot and nworr authored Dec 2, 2024
1 parent e246d68 commit 62ffe5b
Show file tree
Hide file tree
Showing 18 changed files with 1,369 additions and 64 deletions.
3 changes: 2 additions & 1 deletion lizmap/modules/lizmap/lib/App/AppContextInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -269,8 +269,9 @@ public function createJelixForm($formSel, $formId = null);
* Returns the URL corresponding to the Jelix Selector.
*
* @param string $selector The Jelix selector
* @param mixed $params action params
*/
public function getUrl($selector);
public function getUrl($selector, $params = array());

/**
* Returns the absolute Url.
Expand Down
4 changes: 2 additions & 2 deletions lizmap/modules/lizmap/lib/App/JelixContext.php
Original file line number Diff line number Diff line change
Expand Up @@ -326,9 +326,9 @@ public function createJelixForm($formSel, $formId = null)
return \jForms::create($formSel, $formId);
}

public function getUrl($selector)
public function getUrl($selector, $params = array())
{
return \jUrl::get($selector);
return \jUrl::get($selector, $params);
}

public function getFullUrl($selector, $params = array())
Expand Down
71 changes: 71 additions & 0 deletions lizmap/modules/lizmap/lib/Project/ProjectFilesFinder.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
<?php

/**
* @author 3Liz
* @copyright 2024 3liz.com
*
* @see 3liz.com
*
* @license MIT
*/

namespace Lizmap\Project;

class ProjectFilesFinder
{
public function listFileURLS(Project $project, $ignoreRepoAllowUserDefined = false)
{
$jsUrls = array();
$mjsUrls = array();
$cssUrls = array();
if ($ignoreRepoAllowUserDefined || $project->getRepository()->allowUserDefinedThemes()) {
$appContext = $project->getAppContext();
$jsDirArray = array('default', $project->getKey());
$repositoryPath = $project->getRepository()->getPath();
foreach ($jsDirArray as $dir) {
$items = array(
// current repository
'media/js/',
// or root (js shared over repositories)
'../media/js/',
);
foreach ($items as $item) {
$jsPathRoot = realpath($repositoryPath.$item.$dir);
if (!is_dir($jsPathRoot)) {
continue;
}
foreach (new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($jsPathRoot)) as $filename) {
$fileExtension = pathinfo($filename, PATHINFO_EXTENSION);
if ($fileExtension == 'js' || $fileExtension == 'mjs' || $fileExtension == 'css') {
$jsPath = realpath($filename);
$jsRelPath = $item.$dir.str_replace($jsPathRoot, '', $jsPath);
$url = 'view~media:getMedia';
if ($fileExtension == 'css') {
$url = 'view~media:getCssFile';
}

$fileUrl = $appContext->getUrl(
$url,
array(
'repository' => $project->getRepositoryKey(),
'project' => $project->getKey(),
'mtime' => filemtime($filename),
'path' => $jsRelPath,
)
);
if ($fileExtension == 'js') {
$jsUrls[] = $fileUrl;
} elseif ($fileExtension == 'mjs') {
$mjsUrls[] = $fileUrl;
} else {
$cssUrls[] = $fileUrl;
}
}
}
}
}
}

return array('css' => $cssUrls, 'js' => $jsUrls, 'mjs' => $mjsUrls);
}
}
82 changes: 22 additions & 60 deletions lizmap/modules/view/controllers/lizMap.classic.php
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
<?php

use Lizmap\Project\ProjectFilesFinder;
use Lizmap\Request\RemoteStorageRequest;

/**
Expand Down Expand Up @@ -411,66 +412,27 @@ function f($x)
}
}

// Add JS files found in media/js
$jsDirArray = array('default', $project);
foreach ($jsDirArray as $dir) {
$jsUrls = array();
$mjsUrls = array();
$cssUrls = array();
$items = array(
'media/js/',
'../media/js/',
);
foreach ($items as $item) {
$jsPathRoot = realpath($repositoryPath.$item.$dir);
if (is_dir($jsPathRoot)) {
foreach (new RecursiveIteratorIterator(new RecursiveDirectoryIterator($jsPathRoot)) as $filename) {
$fileExtension = pathinfo($filename, PATHINFO_EXTENSION);
if ($fileExtension == 'js' || $fileExtension == 'mjs' || $fileExtension == 'css') {
$jsPath = realpath($filename);
$jsRelPath = $item.$dir.str_replace($jsPathRoot, '', $jsPath);
$url = 'view~media:getMedia';
if ($fileExtension == 'css') {
$url = 'view~media:getCssFile';
}
$jsUrl = jUrl::get(
$url,
array(
'repository' => $lrep->getKey(),
'project' => $project,
'mtime' => filemtime($filename),
'path' => $jsRelPath,
)
);
if ($fileExtension == 'js') {
$jsUrls[] = $jsUrl;
++$countUserJs;
} elseif ($fileExtension == 'mjs') {
$mjsUrls[] = $jsUrl;
++$countUserJs;
} else {
$cssUrls[] = $jsUrl;
}
}
}
}
}

// Add CSS, MJS and JS files ordered by name
sort($cssUrls);
foreach ($cssUrls as $cssUrl) {
$rep->addCSSLink($cssUrl);
}
sort($jsUrls);
foreach ($jsUrls as $jsUrl) {
// Use addHeadContent and not addJSLink to be sure it will be loaded after minified code
$rep->addContent('<script type="text/javascript" defer src="'.$jsUrl.'" ></script>');
}
sort($mjsUrls);
foreach ($mjsUrls as $mjsUrl) {
// Use addHeadContent and not addJSLink to be sure it will be loaded after minified code
$rep->addContent('<script type="module" defer src="'.$mjsUrl.'" ></script>');
}
$fileFinder = new ProjectFilesFinder();
$allURLS = $fileFinder->listFileURLS($lproj);

$cssUrls = $allURLS['css'];
$jsUrls = $allURLS['js'];
$mjsUrls = $allURLS['mjs'];
$countUserJs = count($jsUrls) + count($mjsUrls);
// Add CSS, MJS and JS files ordered by name
sort($cssUrls);
foreach ($cssUrls as $cssUrl) {
$rep->addCSSLink($cssUrl);
}
sort($jsUrls);
foreach ($jsUrls as $jsUrl) {
// Use addHeadContent and not addJSLink to be sure it will be loaded after minified code
$rep->addContent('<script type="text/javascript" defer src="'.$jsUrl.'" ></script>');
}
sort($mjsUrls);
foreach ($mjsUrls as $mjsUrl) {
// Use addHeadContent and not addJSLink to be sure it will be loaded after minified code
$rep->addContent('<script type="module" defer src="'.$mjsUrl.'" ></script>');
}
}
$rep->setBodyAttributes(array('data-lizmap-user-defined-js-count' => $countUserJs));
Expand Down
63 changes: 63 additions & 0 deletions tests/units/classes/Project/ProjectTest.php
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
<?php

use Lizmap\Project;
use Lizmap\Project\ProjectFilesFinder;
use PHPUnit\Framework\TestCase;

/**
Expand Down Expand Up @@ -494,4 +495,66 @@ public function testCheckAcl($aclData, $options, $expectedRet)
$proj->setCfg($config);
$this->assertEquals($expectedRet, $proj->checkAcl());
}

public static function userFiles4Projets() {
$eventsBaseURL = 'view~media:getMedia?repository=repo1&project=events&';
return array(
array(
'montpellier',
'montpellier',
array('path' => __DIR__.'/../../../qgis-projects/demoqgis'),
array(
'css'=> array(),
'mjs' => array(),
'js' => array()
),
),
array(
'events',
'repo1',
array('path' => __DIR__.'/Ressources/root4Repository/repo1'),
array('css'=> array(
'view~media:getCssFile?repository=repo1&project=events&path=media/js/events/style1.css'
),
'mjs' => array(
'view~media:getMedia?repository=repo1&project=events&path=media/js/events/mjs.mjs'
),
'js' => array(
$eventsBaseURL.'path=media/js/default/jsdefaultinrepo.js',
$eventsBaseURL.'path=../media/js/default/jsdefaultinroot.js',
$eventsBaseURL.'path=media/js/events/subfolder/jsinsubfolder.js',
$eventsBaseURL.'path=media/js/events/jsprojetinrepo.js',
$eventsBaseURL.'path=../media/js/events/jsprojetinroot.js',
)
)
)
,
);
}

/**
* @dataProvider userFiles4Projets
*/
public function testFinder(string $projectName, $repoName, array $projectData, array $expectedFiles) {
$repo = new Project\Repository($repoName, $projectData
, null, null, null
);

$project = new ProjectForTests();
$project->setRepo($repo);
$project->setKey($projectName);
$finder = new ProjectFilesFinder();
$listFiles = $finder->listFileURLS($project, true);
foreach($listFiles as $fileExt => $list) {
// remove mtime=XXX From URLs
$urlsWithoutMtime = array_map( function ($url) {
$urlok = preg_replace('/&mtime=[0-9]*/', '', $url);
return $urlok;
}, $list);
// sorting to ensure list are in same order
sort($urlsWithoutMtime);
sort($expectedFiles[$fileExt]);
$this->assertEquals($urlsWithoutMtime, $expectedFiles[$fileExt]);
}
}
}
Empty file.
Empty file.
Loading

0 comments on commit 62ffe5b

Please sign in to comment.