Support CSS .min.css and JavaScript .min.js files in plugins and themes

This commit is contained in:
the-djmaze 2022-11-29 14:59:32 +01:00
parent a492b5bdf9
commit 200e00e2d6
6 changed files with 148 additions and 246 deletions

1
plugins/avatars/avatars.min.js vendored Normal file
View file

@ -0,0 +1 @@
(e=>{const t=[],a=new Map,s=new Map,r="MailMessageView",i=e=>{let t=e.from[0];return`${"pass"==t.dkimStatus?1:0}/${t.email.toLowerCase()}`},o=e=>s.get(e.from[0].email.toLowerCase())||a.get(i(e)),n=(()=>{let s=t.shift();for(;s;){let r=o(s[0]);if(!r){let t=s[0].from[0];e.pluginRemoteRequest(((e,o)=>{!e&&o?.Result.type?(r=`data:${o.Result.type};base64,${o.Result.data}`,a.set(i(s[0]),r),s[1](r)):window.identiconSvg&&window.identiconSvg(t.email).then((e=>{r="data:image/svg+xml;base64,"+btoa(e),a.set(i(s[0]),r),s[1](r)})),n()}),"Avatar",{bimi:"pass"==t.dkimStatus?1:0,email:t.email});break}s[1](r),s=t.shift()}}).debounce(1e3);addEventListener("DOMContentLoaded",(()=>{if(parent.OC){const e=()=>parent.OC,t="DAV:",a="http://nextcloud.com/ns",r="urn:ietf:params:xml:ns:carddav",i=(e,t,a)=>e.getElementsByTagNameNS(t,a),o=(e,t,a)=>i(e,t,a)?.item(0)?.textContent,n=t=>e().webroot+"/remote.php"+t;e().requestToken&&fetch(n(`/dav/addressbooks/users/${e().currentUser}/contacts/`),{mode:"same-origin",cache:"no-cache",redirect:"error",credentials:"same-origin",method:"REPORT",headers:{requesttoken:e().requestToken,"Content-Type":"application/xml; charset=utf-8",Depth:1},body:'<x4:addressbook-query xmlns:x4="urn:ietf:params:xml:ns:carddav"><x0:prop xmlns:x0="DAV:"><x4:address-data><x4:prop name="EMAIL"/></x4:address-data><x3:has-photo xmlns:x3="http://nextcloud.com/ns"/></x0:prop></x4:addressbook-query>'}).then((e=>e.status<400?e.text():Promise.reject(new Error({response:e})))).then((e=>{const n=new DOMParser,d=i(n.parseFromString(e,"application/xml").documentElement,t,"response");for(let e=0;e<d.length;++e){const i=d.item(e);1==o(i,a,"has-photo")&&[...o(i,r,"address-data").matchAll(/EMAIL.*?:([^@\r\n]+@[^@\r\n]+)/g)].forEach((e=>{s.set(e[1].toLowerCase(),o(i,t,"href")+"?photo")}))}}))}})),ko.bindingHandlers.fromPic={init:(e,a,s,r)=>{if(r){let a=o(r),s=t=>{e.src=t};if(a)s(a);else if(r.avatar){let t="pass"==r.from[0].dkimStatus?1:0;window.identiconSvg&&(e.onerror=()=>{window.identiconSvg(r.from[0].email).then((e=>s("data:image/svg+xml;base64,"+btoa(e))))}),s(`?Avatar/${t}/${r.avatar}`)}else t.push([r,s]),n()}}},addEventListener("rl-view-model.create",(e=>{if(r===e.detail.viewModelTemplateID){const a=document.getElementById(r).content.querySelector(".messageItemHeader");a&&a.prepend(Element.fromHTML('<img class="fromPic" data-bind="visible: viewUserPicVisible, attr: {\'src\': viewUserPic() }" loading="lazy">'));let s=e.detail;s.viewUserPic=ko.observable(""),s.viewUserPicVisible=ko.observable(!1),s.message.subscribe((e=>{if(s.viewUserPicVisible(!1),e){let a=o(e),r=e=>{s.viewUserPic(e),s.viewUserPicVisible(!0)};if(a)r(a);else if(e.avatar){r(`?Avatar/${"pass"==e.from[0].dkimStatus?1:0}/${e.avatar}`)}else t.push([e,r]),n()}}))}"MailMessageList"===e.detail.viewModelTemplateID&&document.getElementById("MailMessageList").content.querySelector(".messageCheckbox").append(Element.fromHTML('<img class="fromPic" data-bind="fromPic:$data" loading="lazy">'))}))})(window.rl);

View file

@ -48,7 +48,7 @@ class HSLColor
{
const h = this.h, s = this.s, l = this.l/*, a = this.a*/,
hex = v => {
v = Math.max(0, Math.min(255, v * 255)).toString(16);
v = between(0, 255, v * 255).toString(16);
return v.slice(0,2).padStart(2, "0");
};
let r=l, g=l, b=l;
@ -68,6 +68,8 @@ class HSLColor
}
const
between = (l, h, v) => Math.max(l, Math.min(h, v)),
parseHex = (hash, startPosition, octets) => parseInt(hash.substr(startPosition, octets), 16),
/**
@ -86,99 +88,17 @@ const
lightness = lightness < 0.5 ? lightness * corrector * 2 : corrector + (lightness - 0.5) * (1 - corrector) * 2;
return new HSLColor(hue, saturation, lightness).toString();
},
/**
* Gets the normalized current Jdenticon color configuration. Missing fields have default values.
* @param {Object|number|undefined} paddingOrLocalConfig - Configuration passed to the called API method. A
* local configuration overrides the global configuration in it entirety. This parameter can for backward
* compatibility also contain a padding value. A padding value only overrides the global padding, not the
* entire global configuration.
* @param {number} defaultPadding - Padding used if no padding is specified in neither the configuration nor
* explicitly to the API method.
* @returns {ParsedConfiguration}
*/
getConfiguration = (paddingOrLocalConfig, defaultPadding) => {
const configObject =
typeof paddingOrLocalConfig == "object" && paddingOrLocalConfig ||
{ },
lightnessConfig = configObject["lightness"] || { },
// In versions < 2.1.0 there was no grayscale saturation -
// saturation was the color saturation.
saturation = configObject["saturation"] || { },
colorSaturation = "color" in saturation ? saturation["color"] : saturation,
grayscaleSaturation = saturation["grayscale"],
padding = configObject["padding"],
/**
* Creates a lightness range.
*/
lightness = (configName, defaultRange) => {
var range = lightnessConfig[configName];
// Check if the lightness range is an array-like object. This way we ensure the
// array contain two values at the same time.
if (!(range && range.length > 1)) {
range = defaultRange;
}
/**
* Gets a lightness relative the specified value in the specified lightness range.
*/
return function (value) {
value = range[0] + value * (range[1] - range[0]);
return value < 0 ? 0 : value > 1 ? 1 : value;
};
};
return {
/**
* Gets a hue allowed by the configured hue restriction,
* provided the originally computed hue.
*/
X/*hue*/: originalHue => {
var hueConfig = configObject["hues"];
var hue;
// Check if 'hues' is an array-like object. This way we also ensure that
// the array is not empty, which would mean no hue restriction.
if (hueConfig && hueConfig.length > 0) {
// originalHue is in the range [0, 1]
// Multiply with 0.999 to change the range to [0, 1) and then truncate the index.
hue = hueConfig[0 | (0.999 * originalHue * hueConfig.length)];
}
return typeof hue == "number" ?
// A hue was specified. We need to convert the hue from
// degrees on any turn - e.g. 746° is a perfectly valid hue -
// to turns in the range [0, 1).
((((hue / 360) % 1) + 1) % 1) :
// No hue configured => use original hue
originalHue;
},
p/*colorSaturation*/: typeof colorSaturation == "number" ? colorSaturation : 0.5,
H/*grayscaleSaturation*/: typeof grayscaleSaturation == "number" ? grayscaleSaturation : 0,
q/*colorLightness*/: lightness("color", [0.4, 0.8]),
I/*grayscaleLightness*/: lightness("grayscale", [0.3, 0.9]),
Y/*iconPadding*/:
typeof paddingOrLocalConfig == "number" ? paddingOrLocalConfig :
typeof padding == "number" ? padding :
defaultPadding
}
};
/**
* Represents a point.
*/
function Point(x, y) {
class Point
{
constructor(x, y) {
this.x = x;
this.y = y;
}
}
/**
@ -466,106 +386,6 @@ function outerShape(index, g, cell) {
);
}
/**
* Gets a set of identicon color candidates for a specified hue and config.
* @param {number} hue
* @param {ParsedConfiguration} config
*/
function colorTheme(hue, config) {
hue = config.X/*hue*/(hue);
return [
// Dark gray
correctedHsl(hue, config.H/*grayscaleSaturation*/, config.I/*grayscaleLightness*/(0)),
// Mid color
correctedHsl(hue, config.p/*colorSaturation*/, config.q/*colorLightness*/(0.5)),
// Light gray
correctedHsl(hue, config.H/*grayscaleSaturation*/, config.I/*grayscaleLightness*/(1)),
// Light color
correctedHsl(hue, config.p/*colorSaturation*/, config.q/*colorLightness*/(1)),
// Dark color
correctedHsl(hue, config.p/*colorSaturation*/, config.q/*colorLightness*/(0))
];
}
/**
* Draws an identicon to a specified renderer.
* @param {Renderer} renderer
* @param {string} hash
* @param {Object|number=} config
*/
function iconGenerator(renderer, hash, config) {
var parsedConfig = getConfiguration(config, 0.08);
// Calculate padding and round to nearest integer
var size = renderer.k/*iconSize*/;
var padding = (0.5 + size * parsedConfig.Y/*iconPadding*/) | 0;
size -= padding * 2;
var graphics = new Graphics(renderer);
// Calculate cell size and ensure it is an integer
var cell = 0 | (size / 4);
// Since the cell size is integer based, the actual icon will be slightly smaller than specified => center icon
var x = 0 | (padding + size / 2 - cell * 2);
var y = 0 | (padding + size / 2 - cell * 2);
function renderShape(colorIndex, shapes, index, rotationIndex, positions) {
var shapeIndex = parseHex(hash, index, 1);
var r = rotationIndex ? parseHex(hash, rotationIndex, 1) : 0;
renderer.O/*beginShape*/(availableColors[selectedColorIndexes[colorIndex]]);
for (var i = 0; i < positions.length; i++) {
graphics.A/*currentTransform*/
= new Transform(x + positions[i][0] * cell, y + positions[i][1] * cell, cell, r++ % 4);
shapes(shapeIndex, graphics, cell, i);
}
renderer.P/*endShape*/();
}
// AVAILABLE COLORS
var hue = parseHex(hash, -7) / 0xfffffff,
// Available colors for this icon
availableColors = colorTheme(hue, parsedConfig),
// The index of the selected colors
selectedColorIndexes = [];
var index;
function isDuplicate(values) {
if (values.indexOf(index) >= 0) {
for (var i = 0; i < values.length; i++) {
if (selectedColorIndexes.indexOf(values[i]) >= 0) {
return true;
}
}
}
}
for (var i = 0; i < 3; i++) {
index = parseHex(hash, 8 + i, 1) % availableColors.length;
if (isDuplicate([0, 4]) || // Disallow dark gray and dark color combo
isDuplicate([2, 3])) { // Disallow light gray and light color combo
index = 1;
}
selectedColorIndexes.push(index);
}
// ACTUAL RENDERING
// Sides
renderShape(0, outerShape, 2, 3, [[1, 0], [2, 0], [2, 3], [1, 3], [0, 1], [3, 1], [3, 2], [0, 2]]);
// Corners
renderShape(1, outerShape, 4, 5, [[0, 0], [3, 0], [3, 3], [0, 3]]);
// Center
renderShape(2, centerShape, 1, null, [[1, 1], [2, 1], [2, 2], [1, 2]]);
renderer.finish();
}
/**
* Computes a SHA1 hash for any value and returns it as a hexadecimal string.
*
@ -775,18 +595,99 @@ class SvgWriter
/**
* Draws an identicon as an SVG string.
* @param {*} hashOrValue - A hexadecimal hash string or any value that will be hashed by Jdenticon.
* @param {number} size - Icon size in pixels.
* @param {Object|number=} config - Optional configuration. If specified, this configuration object overrides any
* global configuration in its entirety. For backward compatibility a padding value in the range [0.0, 0.5) can be
* specified in place of a configuration object.
* @returns {string} SVG string
*/
window.identiconSvg = async (hashOrValue, config) => {
var writer = new SvgWriter(50);
iconGenerator(new SvgRenderer(writer),
(/^[0-9a-f]{11,}$/i.test(hashOrValue) && hashOrValue)
window.identiconSvg = async (hashOrValue) => {
const writer = new SvgWriter(50),
renderer = new SvgRenderer(writer),
hash = (/^[0-9a-f]{11,}$/i.test(hashOrValue) && hashOrValue)
|| await computeHash(hashOrValue == null ? "" : "" + hashOrValue),
config);
config = {
p/*colorSaturation*/: 0.5,
H/*grayscaleSaturation*/: 0,
q/*colorLightness*/: value => between(0, 1, 0.4 + value * (0.8 - 0.4)),
I/*grayscaleLightness*/: value => between(0, 1, 0.3 + value * (0.9 - 0.3))
};
var index;
// Calculate padding and round to nearest integer
var size = renderer.k/*iconSize*/;
var padding = (0.5 + size * 0.08) | 0;
size -= padding * 2;
const graphics = new Graphics(renderer),
// Calculate cell size and ensure it is an integer
cell = 0 | (size / 4),
// Since the cell size is integer based, the actual icon will be slightly smaller than specified => center icon
s = 0 | (padding + size / 2 - cell * 2),
// AVAILABLE COLORS
hue = parseHex(hash, -7) / 0xfffffff,
// Available colors for this icon
availableColors = [
// Dark gray
correctedHsl(hue, config.H/*grayscaleSaturation*/, config.I/*grayscaleLightness*/(0)),
// Mid color
correctedHsl(hue, config.p/*colorSaturation*/, config.q/*colorLightness*/(0.5)),
// Light gray
correctedHsl(hue, config.H/*grayscaleSaturation*/, config.I/*grayscaleLightness*/(1)),
// Light color
correctedHsl(hue, config.p/*colorSaturation*/, config.q/*colorLightness*/(1)),
// Dark color
correctedHsl(hue, config.p/*colorSaturation*/, config.q/*colorLightness*/(0))
],
// The index of the selected colors
selectedColorIndexes = [],
isDuplicate = values => {
if (values.indexOf(index) >= 0) {
for (var i = 0; i < values.length; i++) {
if (selectedColorIndexes.indexOf(values[i]) >= 0) {
return true;
}
}
}
},
renderShape = (colorIndex, shapes, index, rotationIndex, positions) => {
var shapeIndex = parseHex(hash, index, 1);
var r = rotationIndex ? parseHex(hash, rotationIndex, 1) : 0;
renderer.O/*beginShape*/(availableColors[selectedColorIndexes[colorIndex]]);
for (var i = 0; i < positions.length; i++) {
graphics.A/*currentTransform*/
= new Transform(s + positions[i][0] * cell, s + positions[i][1] * cell, cell, r++ % 4);
shapes(shapeIndex, graphics, cell, i);
}
renderer.P/*endShape*/();
};
for (var i = 0; i < 3; i++) {
index = parseHex(hash, 8 + i, 1) % availableColors.length;
if (isDuplicate([0, 4]) || // Disallow dark gray and dark color combo
isDuplicate([2, 3])) { // Disallow light gray and light color combo
index = 1;
}
selectedColorIndexes.push(index);
}
// ACTUAL RENDERING
// Sides
renderShape(0, outerShape, 2, 3, [[1, 0], [2, 0], [2, 3], [1, 3], [0, 1], [3, 1], [3, 2], [0, 2]]);
// Corners
renderShape(1, outerShape, 4, 5, [[0, 0], [3, 0], [3, 3], [0, 3]]);
// Center
renderShape(2, centerShape, 1, null, [[1, 1], [2, 1], [2, 2], [1, 2]]);
renderer.finish();
return writer.toString();
};

1
plugins/avatars/jdenticon.min.js vendored Normal file
View file

@ -0,0 +1 @@
(()=>{class t{constructor(t,i,s){this.h=t,this.s=i,this.l=s}toString(){const t=this.h,s=this.s,h=this.l,r=t=>(t=i(0,255,255*t).toString(16)).slice(0,2).padStart(2,"0");let n=h,e=h,a=h;if(0!=s){let i=h<.5?h*(s+1):h+s-h*s,r=2*h-i,o=t=>6*(t+=t<0?1:t>1?-1:0)<1?r+(i-r)*t*6:2*t<1?i:3*t<2?r+(i-r)*(2/3-t)*6:r;n=o(t+1/3),e=o(t),a=o(t-1/3)}return"#"+r(n)+r(e)+r(a)}}const i=(t,i,s)=>Math.max(t,Math.min(i,s)),s=(t,i,s)=>parseInt(t.substr(i,s),16),h=(i,s,h)=>{var r=[.55,.5,.5,.46,.6,.55,.55][6*i+.5|0];return new t(i,s,h=h<.5?h*r*2:r+(h-.5)*(1-r)*2).toString()};class r{constructor(t,i){this.x=t,this.y=i}}class n{constructor(t,i,s,h){this.u=t,this.v=i,this.K=s,this.Z=h}L(t,i,s,h){var n=this.u+this.K,e=this.v+this.K,a=this.Z;return 1===a?new r(n-i-(h||0),this.v+t):2===a?new r(n-t-(s||0),e-i-(h||0)):3===a?new r(this.u+i,e-t-(s||0)):new r(this.u+t,this.v+i)}}var e=new n(0,0,0,0);class a{constructor(t){this.M=t,this.A=e}g(t,i){for(var s=i?-2:2,h=[],r=i?t.length-2:0;r<t.length&&r>=0;r+=s)h.push(this.A.L(t[r],t[r+1]));this.M.g(h)}h(t,i,s,h){var r=this.A.L(t,i,s,s);this.M.h(r,s,h)}i(t,i,s,h,r){this.g([t,i,t+s,i,t+s,i+h,t,i+h],r)}j(t,i,s,h,r,n){var e=[t+s,i,t+s,i+h,t,i+h,t,i];e.splice((r||0)%4*2,2),this.g(e,n)}N(t,i,s,h,r){this.g([t+s/2,i,t+s,i+h/2,t+s/2,i+h,t,i+h/2],r)}}function o(t,i,s,h){var r,n,e,a,o,c;(t%=14)?1==t?(e=0|.5*s,a=0|.8*s,i.j(s-e,0,e,a,2)):2==t?(e=0|s/3,i.i(e,e,s-e,s-e)):3==t?(c=s<6?1:s<8?2:0|.25*s,o=(o=.1*s)>1?0|o:o>.5?1:o,i.i(c,c,s-o-c,s-o-c)):4==t?(n=0|.15*s,e=0|.5*s,i.h(s-e-n,s-e-n,e)):5==t?((c=4*(o=.1*s))>3&&(c|=0),i.i(0,0,s,s),i.g([c,c,s-o,c,c+(s-c-o)/2,s-o],!0)):6==t?i.g([0,0,s,0,s,.7*s,.4*s,.4*s,.7*s,s,0,s]):7==t?i.j(s/2,s/2,s/2,s/2,3):8==t?(i.i(0,0,s,s/2),i.i(0,s/2,s/2,s/2),i.j(s/2,s/2,s/2,s/2,1)):9==t?(o=.14*s,c=s<4?1:s<6?2:0|.35*s,o=s<8?o:0|o,i.i(0,0,s,s),i.i(c,c,s-c-o,s-c-o,!0)):10==t?(c=3*(o=.12*s),i.i(0,0,s,s),i.h(c,c,s-o-c,!0)):11==t?i.j(s/2,s/2,s/2,s/2,3):12==t?(n=.25*s,i.i(0,0,s,s),i.N(n,n,s-n,s-n,!0)):!h&&(n=.4*s,e=1.2*s,i.h(n,n,e)):(r=.42*s,i.g([0,0,s,0,s,s-2*r,s-r,s,0,s]))}function c(t,i,s){var h;(t%=4)?1==t?i.j(0,s/2,s,s/2,0):2==t?i.N(0,0,s,s):(h=s/6,i.h(h,h,s-2*h)):i.j(0,0,s,s,0)}function g(t){return(10*t+.5|0)/10}class l{constructor(){this.B=""}g(t){for(var i="",s=0;s<t.length;s++)i+=(s?"L":"M")+g(t[s].x)+" "+g(t[s].y);this.B+=i+"Z"}h(t,i,s){var h=s?0:1,r=g(i/2),n=g(i),e="a"+r+","+r+" 0 1,"+h+" ";this.B+="M"+g(t.x)+" "+g(t.y+i/2)+e+n+",0"+e+-n+",0"}}class u{constructor(t){this.C,this.D={},this.R=t,this.k=t.k}m(t){var i=/^(#......)(..)?/.exec(t),h=i[2]?s(i[2],0)/255:1;this.R.m(i[1],h)}O(t){this.C=this.D[t]||(this.D[t]=new l)}P(){}g(t){this.C.g(t)}h(t,i,s){this.C.h(t,i,s)}finish(){var t=this.D;for(var i in t)t.hasOwnProperty(i)&&this.R.S(i,t[i].B)}}class v{constructor(t){this.k=t,this.F='<svg xmlns="http://www.w3.org/2000/svg" width="'+t+'" height="'+t+'" viewBox="0 0 '+t+" "+t+'">'}m(t,i){i&&(this.F+='<rect width="100%" height="100%" fill="'+t+'" opacity="'+i.toFixed(2)+'"/>')}S(t,i){this.F+='<path fill="'+t+'" d="'+i+'"/>'}toString(){return this.F+"</svg>"}}window.identiconSvg=async t=>{const r=new v(50),e=new u(r),g=/^[0-9a-f]{11,}$/i.test(t)&&t||await async function(t){return Array.from(new Uint8Array(await crypto.subtle.digest("SHA-1",(new TextEncoder).encode(t)))).map((t=>t.toString(16).padStart(2,"0"))).join("")}(null==t?"":""+t),l=.5,w=0,f=t=>i(0,1,.4+.4*t),d=t=>i(0,1,.3+t*(.9-.3));var p,S=e.k,x=.5+.08*S|0;S-=2*x;const y=new a(e),j=0|S/4,m=0|x+S/2-2*j,A=s(g,-7)/268435455,M=[h(A,w,d(0)),h(A,l,f(.5)),h(A,w,d(1)),h(A,l,f(1)),h(A,l,f(0))],B=[],F=t=>{if(t.indexOf(p)>=0)for(var i=0;i<t.length;i++)if(B.indexOf(t[i])>=0)return!0},O=(t,i,h,r,a)=>{var o=s(g,h,1),c=r?s(g,r,1):0;e.O(M[B[t]]);for(var l=0;l<a.length;l++)y.A=new n(m+a[l][0]*j,m+a[l][1]*j,j,c++%4),i(o,y,j,l);e.P()};for(var k=0;k<3;k++)p=s(g,8+k,1)%M.length,(F([0,4])||F([2,3]))&&(p=1),B.push(p);return O(0,c,2,3,[[1,0],[2,0],[2,3],[1,3],[0,1],[3,1],[3,2],[0,2]]),O(1,c,4,5,[[0,0],[3,0],[3,3],[0,3]]),O(2,o,1,null,[[1,1],[2,1],[2,2],[1,2]]),e.finish(),r.toString()}})();

View file

@ -92,7 +92,7 @@ trait Themes
return \in_array($sTheme, $this->GetThemes()) ? $sTheme : $this->Config()->Get('themes', 'default', 'Default');
}
public function compileCss(string $sTheme, bool $bAdmin) : string
public function compileCss(string $sTheme, bool $bAdmin, bool $bMinified = false) : string
{
$bCustomTheme = '@custom' === \substr($sTheme, -7);
if ($bCustomTheme) {
@ -118,7 +118,7 @@ trait Themes
}
}
$mResult[] = $this->Plugins()->CompileCss($bAdmin, $bLess);
$mResult[] = $this->Plugins()->CompileCss($bAdmin, $bLess, $bMinified);
$mResult = \preg_replace('@(url\(["\']?)(\\./)?([a-z]+[^:a-z])@',
"\$1{$sBase}\$3",

View file

@ -179,11 +179,17 @@ class Manager
return $this->bIsEnabled && \count($this->aJs[$bAdminScope ? 1 : 0]);
}
public function CompileCss(bool $bAdminScope, bool &$bLess) : string
public function CompileCss(bool $bAdminScope, bool &$bLess, bool $bMinified) : string
{
$aResult = array();
if ($this->bIsEnabled) {
foreach ($this->aCss[$bAdminScope ? 1 : 0] as $sFile) {
if ($bMinified) {
$sMinFile = \str_replace('.css', '.min.css', $sFile);
if (\is_readable($sMinFile)) {
$sFile = $sMinFile;
}
}
if (\is_readable($sFile)) {
$aResult[] = \file_get_contents($sFile);
$bLess = $bLess || \str_ends_with($sFile, '.less');
@ -193,15 +199,18 @@ class Manager
return \implode("\n", $aResult);
}
public function CompileJs(bool $bAdminScope = false) : string
public function CompileJs(bool $bAdminScope = false, bool $bMinified = false) : string
{
$aResult = array();
if ($this->bIsEnabled)
{
foreach ($this->aJs[$bAdminScope ? 1 : 0] as $sFile)
{
if (\is_readable($sFile))
{
if ($this->bIsEnabled) {
foreach ($this->aJs[$bAdminScope ? 1 : 0] as $sFile) {
if ($bMinified) {
$sMinFile = \str_replace('.js', '.min.js', $sFile);
if (\is_readable($sMinFile)) {
$sFile = $sMinFile;
}
}
if (\is_readable($sFile)) {
$aResult[] = \file_get_contents($sFile);
}
}

View file

@ -506,31 +506,29 @@ class ServiceActions
\header('Content-Type: application/javascript; charset=utf-8');
$bCacheEnabled = $this->Config()->Get('labs', 'cache_system_data', true);
if ($bCacheEnabled)
{
$this->oActions->verifyCacheByKey($this->sQuery);
$bAppDebug = $this->Config()->Get('debug', 'enable', false);
$sMinify = ($bAppDebug || $this->Config()->Get('labs', 'use_app_debug_js', false)) ? '' : 'min';
$bCacheEnabled = !$bAppDebug && $this->Config()->Get('labs', 'cache_system_data', true);
if ($bCacheEnabled) {
$this->oActions->verifyCacheByKey($this->sQuery . $sMinify);
}
$sCacheFileName = '';
if ($bCacheEnabled)
{
$sCacheFileName = KeyPathHelper::PluginsJsCache($this->oActions->Plugins()->Hash());
if ($bCacheEnabled) {
$sCacheFileName = KeyPathHelper::PluginsJsCache($this->oActions->Plugins()->Hash()) . $sMinify;
$sResult = $this->Cacher()->Get($sCacheFileName);
}
if (!\strlen($sResult))
{
$sResult = $this->Plugins()->CompileJs($bAdmin);
if ($bCacheEnabled && \strlen($sCacheFileName))
{
if (!$sResult) {
$sResult = $this->Plugins()->CompileJs($bAdmin, !!$sMinify);
if ($sCacheFileName) {
$this->Cacher()->Set($sCacheFileName, $sResult);
}
}
if ($bCacheEnabled)
{
$this->oActions->cacheByKey($this->sQuery);
if ($bCacheEnabled) {
$this->oActions->cacheByKey($this->sQuery . $sMinify);
}
return $sResult;
@ -539,45 +537,38 @@ class ServiceActions
public function ServiceCss() : string
{
$sResult = '';
$bAdmin = !empty($this->aPaths[2]) && 'Admin' === $this->aPaths[2];
$bJson = !empty($this->aPaths[9]) && 'Json' === $this->aPaths[9];
if ($bJson)
{
if ($bJson) {
\header('Content-Type: application/json; charset=utf-8');
}
else
{
} else {
\header('Content-Type: text/css; charset=utf-8');
}
$sTheme = '';
if (!empty($this->aPaths[4]))
{
if (!empty($this->aPaths[4])) {
$sTheme = $this->oActions->ValidateTheme($this->aPaths[4]);
$bCacheEnabled = $this->Config()->Get('labs', 'cache_system_data', true);
if ($bCacheEnabled)
{
$this->oActions->verifyCacheByKey($this->sQuery);
$bAppDebug = $this->Config()->Get('debug', 'enable', false);
$sMinify = ($bAppDebug || $oConfig->Get('labs', 'use_app_debug_css', false)) ? '' : 'min';
$bCacheEnabled = !$bAppDebug && $this->Config()->Get('labs', 'cache_system_data', true);
if ($bCacheEnabled) {
$this->oActions->verifyCacheByKey($this->sQuery . $sMinify);
}
$sCacheFileName = '';
if ($bCacheEnabled)
{
$sCacheFileName = KeyPathHelper::CssCache($sTheme, $this->oActions->Plugins()->Hash());
if ($bCacheEnabled) {
$sCacheFileName = KeyPathHelper::CssCache($sTheme, $this->oActions->Plugins()->Hash()) . $sMinify;
$sResult = $this->Cacher()->Get($sCacheFileName);
}
if (!$sResult)
{
if (!$sResult) {
try
{
$sResult = $this->oActions->compileCss($sTheme, $bAdmin);
if ($bCacheEnabled && $sCacheFileName)
{
if ($sCacheFileName) {
$this->Cacher()->Set($sCacheFileName, $sResult);
}
}
@ -587,9 +578,8 @@ class ServiceActions
}
}
if ($bCacheEnabled)
{
$this->oActions->cacheByKey($this->sQuery);
if ($bCacheEnabled) {
$this->oActions->cacheByKey($this->sQuery . $sMinify);
}
}