Version 5.0.13

This commit is contained in:
Neo committed 2025-12-19 19:04:57 -08:00
1 parent b89858b2ff
commit 5efe744c5f
1407 files changed
+69690 -30177

No files matched your search

+129 -5
View File
@@ -51,10 +51,15 @@ use function is_dir;
use function is_file;
use function is_string;
use function json_encode;
use function mb_strtolower;
use function md5;
use function mkdir;
use function preg_match;
use function rtrim;
use function str_ends_with;
use function substr;
use function unlink;
use function urlencode;
use const IPS\CACHEBUST_KEY;
use const IPS\IPS_FILE_PERMISSION;
use const IPS\IPS_FOLDER_PERMISSION;
@@ -891,10 +896,38 @@ class Javascript extends ActiveRecord
'javascript_app, javascript_location, javascript_position'
)->setKeyField('javascript_id') );
/* Web Components are not loaded along with the rest of dev/js/framework */
$locationRows = [];
$componentRows = [];
foreach ( $rows as $id => $row )
{
if ( $fileName === 'framework.js' and $row['javascript_type'] === 'component' )
{
$componentRows[$id] = $row;
}
else
{
$locationRows[$id] = $row;
}
}
/* Write it */
$obj = static::_writeJavascriptFromResultset( $rows, $fileName, $app, 'root' );
$obj = static::_writeJavascriptFromResultset( $locationRows, $fileName, $app, 'root' );
$map[ $app ][ md5( $app .'-' . 'root' . '-' . $fileName ) ] = $obj ? (string) $obj : null;
/* Web Components should have their own file */
foreach ( $componentRows as $id => $row )
{
$componentName = explode( '.', $row['javascript_name'] )[0];
if ( !preg_match( "/^[a-zA-Z][a-zA-Z0-9]*$/", $componentName ) )
{
continue;
}
$row['javascript_content'] = static::wrapWebComponentContents( $row['javascript_content'], $componentName );
$componentObj = static::_writeJavascriptFromResultset( [ $id => $row ], "component_" . $row['javascript_name'], $app, 'root' );
$map[ $app ][ md5( $app . '-root-' . "component_" . $row['javascript_name'] ) ] = $componentObj ? (string) $componentObj : null;
}
}
}
}
@@ -1170,7 +1203,7 @@ class Javascript extends ActiveRecord
*
* @param string $file Filename
* @param string|null $app Application
* @param string|null $location Location (e.g. 'admin', 'front')
* @param string|null $location Location (e.g. 'admin', 'front', 'components')
* @return array URL to JS files
*/
public static function inDevJs( string $file, string $app=NULL, string $location=NULL ): array
@@ -1189,6 +1222,16 @@ class Javascript extends ActiveRecord
$location = '/';
}
}
// Loading a web component? we then need to load from the file directly
if ( $location === "components" )
{
if ( str_ends_with( $file, '.js' ) )
{
$file = mb_substr( $file, 0, -3 );
}
return array( Url::baseUrl() . "/applications/core/interface/js/webcomponents.php?component=" . urlencode( $file ) );
}
$app = $app ?: ( Dispatcher::i()->application ? Dispatcher::i()->application->directory : NULL );
$location = $location ?: Dispatcher::i()->controllerLocation;
@@ -1223,7 +1266,7 @@ class Javascript extends ActiveRecord
{
return static::_directoryJs( ROOT_PATH . "/dev/js/" . mb_substr( $file, 0, -3 ) );
}
$path = ROOT_PATH . "/dev/js";
}
else
@@ -1407,8 +1450,9 @@ class Javascript extends ActiveRecord
{
continue;
}
if ( $file->isDir() )
// Skip the /framework/common/components directory
if ( $file->isDir() && !( str_ends_with( $path, 'dev/js/framework/common' ) and rtrim( $file->getFilename(), '/' ) == 'components' ) )
{
$return = static::_directoryJs( $path . '/' . $file->getFileName(), $return );
}
@@ -1508,6 +1552,10 @@ class Javascript extends ActiveRecord
{
$type = 'mixins';
}
else if ( mb_strstr( $path, '/components/' ) )
{
$type = 'component';
}
else if ( mb_strstr( $path, '/ui/' ) )
{
$type = 'ui';
@@ -1572,4 +1620,80 @@ class Javascript extends ActiveRecord
return $map;
}
/**
* Wrap contents with the web components
*
* @param string $contents
* @param string $component The component's file name
* @return string
*/
protected static function wrapWebComponentContents( string $contents, string $component ) : string
{
/* Start with some light validation to make sure the component is a valid string */
if ( !preg_match( '/^[a-zA-Z][a-zA-Z0-9]*$/', $component ) )
{
throw new InvalidArgumentException( "The name {$component} is invalid. Expected an alphanumeric string (camel case)" );
}
$encodedComponent = json_encode( $component );
$errorStatement = <<<JS
Debug.log(`The source file for the component \${{$encodedComponent}} does not contain a class that extends HTMLElement. If the component extends a class other than HTMLElement, ips.ui.registerWebComponent() will need to be invoked directly.`);
JS;
if ( preg_match( "/class\s+([a-zA-Z][a-zA-Z0-9]*)\s+extends\s+HTMLElement/", $contents, $matches ) )
{
$classStatement = <<<JS
ips.ui.registerWebComponent( {$encodedComponent}, {$matches[1]} );
Debug.log(`Submitted the web component constructor, {$matches[1]}, for \${{$encodedComponent}}`);
JS;
}
else
{
$classStatement = $errorStatement;
}
return <<<JS
;(function() {
"use strict";
{$contents}
{$classStatement}
})();
JS;
}
/**
* Generate the JS that defines a Web Component
*
* @param string $component
*
* @return string
*/
public static function generateWebComponent( string $component ) : string
{
/* Start with some light validation to make sure the component is a valid string */
if ( !preg_match( '/^[a-zA-Z][a-zA-Z0-9]*$/', $component ) )
{
throw new InvalidArgumentException( "The name {$component} is invalid. Expected an alphanumeric string (camel case)" );
}
if ( \IPS\IN_DEV )
{
$path = Application::getRootPath() . '/dev/js/framework/common/components/' . $component . '.js';
if ( file_exists( $path ) and $contents = file_get_contents( $path ) )
{
return static::wrapWebComponentContents( $contents, $component );
}
}
else
{
$path = Application::getRootPath() . "static/js/global/root_component_" . $component . 'js';
if ( file_exists( $path ) and $contents = file_get_contents( $path ) )
{
return $contents;
}
}
throw new OutOfRangeException( "Cannot find file $path" );
}
}