Compare commits
481 Commits
Author | SHA1 | Date | |
---|---|---|---|
1f0347682e | |||
1aee385679 | |||
5dd8191692 | |||
b6422f9b80 | |||
a6c2c9c92f | |||
247c573a6e | |||
aa435d6e94 | |||
f6858c221b | |||
437aa4510b | |||
430572fb32 | |||
9f0b755d6f | |||
66acb55a57 | |||
f936d4c36e | |||
c3ddb8df56 | |||
81ce920e69 | |||
3cb875d139 | |||
fdb217d5c6 | |||
085cae3b5f | |||
e2f99a1554 | |||
aee0c27da7 | |||
accbf4ad8b | |||
0ac1901f6b | |||
c0a0deea78 | |||
e3f099441c | |||
840dd25cd1 | |||
a493969f9b | |||
cca42a10a1 | |||
2f4aa98c3c | |||
175cb9588c | |||
a8976e7559 | |||
b663528fb0 | |||
1a2ad55677 | |||
513d2a88c0 | |||
57ef4c0396 | |||
e9599ca2f4 | |||
2fc6dbc222 | |||
225933c442 | |||
36e2f048d7 | |||
0e158bce59 | |||
202201fd31 | |||
4f8c928f44 | |||
ada062cf00 | |||
32dc12912a | |||
671d21adf4 | |||
4e3f8e4b67 | |||
586bb62073 | |||
151bf83ab1 | |||
8c618edb5a | |||
6d6b0cf8c9 | |||
c610608890 | |||
28da61daab | |||
cbfc90f60b | |||
fec92959d4 | |||
bb00d81eba | |||
bb55644c06 | |||
16215847cd | |||
8ee9aed817 | |||
515c6402b9 | |||
d1b94ec203 | |||
a037d9167e | |||
3054d33e62 | |||
6651e641e1 | |||
35f873a342 | |||
2d03ff38a1 | |||
44a3db417b | |||
f9ca702a12 | |||
4073ff38eb | |||
f0e2c9f1b6 | |||
cf040f51b5 | |||
dcf919fb36 | |||
aa19b81a68 | |||
db8d77365c | |||
280eaea84a | |||
340ef46469 | |||
a5f8651941 | |||
8a18ee548e | |||
ef791aa22a | |||
4bdf2e1cc0 | |||
ffa0ca9379 | |||
d3b3d46fc1 | |||
7e7dd8efa9 | |||
b4506f1133 | |||
7350c79113 | |||
5f7b60d3f4 | |||
266495a611 | |||
f5b4a7e77b | |||
51ed0f6487 | |||
bd70def18a | |||
93a9cf3b31 | |||
751287999f | |||
d433850cbf | |||
c93e70e2dc | |||
a129dd989a | |||
40999c3ff4 | |||
18a01d672c | |||
3648f99920 | |||
e823412f56 | |||
d090f446c9 | |||
19985d1742 | |||
ab52251116 | |||
acb6c0187c | |||
90f9c24720 | |||
415bec4646 | |||
5559f20511 | |||
6ea3399829 | |||
9e3df97737 | |||
0ac40a4d77 | |||
24bf5e8102 | |||
56eebb03c7 | |||
1cd4d6d0df | |||
22d4a8232a | |||
48076c25bf | |||
478a308e73 | |||
8ca2f0a49f | |||
4a35d7364b | |||
8b2e55a969 | |||
9b14b70687 | |||
1c01087eda | |||
5137e5a301 | |||
0fea8365b8 | |||
116a615b84 | |||
ef272dd6a8 | |||
4462ae9cae | |||
66ffad0b4e | |||
81e0fc940c | |||
3e8794db1b | |||
617622d4d8 | |||
a4240f972b | |||
42feff8882 | |||
70edd9686f | |||
d298cb2e1c | |||
3fef3f2dc3 | |||
c85f9d6ae4 | |||
85e7ac7cd7 | |||
5c7db61a7e | |||
497f9ca0b1 | |||
0c50f7a322 | |||
740bcbd12c | |||
c92be4f270 | |||
e2a7271ab2 | |||
64766713fa | |||
59bba83b1d | |||
8ac1217165 | |||
5443629ec5 | |||
8f9b41cb62 | |||
7df5eba775 | |||
e29c6ac593 | |||
4f3190bf73 | |||
f0878fccb5 | |||
b0e121a53f | |||
eda48ab0e6 | |||
6a1014d8c1 | |||
e0f87315bc | |||
f2c5dca5e7 | |||
3c435a804f | |||
7ee6775251 | |||
98adc2ecc1 | |||
45afbbdac6 | |||
a18260747b | |||
0c80e28754 | |||
719bc374ac | |||
d7a290c595 | |||
4b2bd33baa | |||
efbe4d697c | |||
a8662bdb8b | |||
d822225465 | |||
c6373ef582 | |||
5a2af6d0f9 | |||
52000d6a41 | |||
befa13eaf2 | |||
4ac68a81a3 | |||
71e472f330 | |||
ada8809ec0 | |||
25ea518266 | |||
f3720c3b94 | |||
b942a84b15 | |||
574ca90229 | |||
5610a14e49 | |||
c5bc62e6df | |||
e9f6a85cad | |||
8921011b27 | |||
90ef3f6c94 | |||
e84c75f4a8 | |||
68e20cd860 | |||
76bdcea4b1 | |||
f758cb7e6e | |||
1108477810 | |||
deb6a9e51c | |||
9660f20b87 | |||
4d26468ede | |||
125a0979d5 | |||
98bdfd3dbe | |||
ea72880e74 | |||
17fec7d6e1 | |||
d9de64604e | |||
6275ab23ff | |||
8c0271643d | |||
c3f041dc87 | |||
80e5e84341 | |||
938eee80a9 | |||
7abc2289de | |||
bb79b9ed74 | |||
1e89a8625c | |||
90b0f04b3c | |||
0f019cd9b6 | |||
1209739398 | |||
b99db2b353 | |||
f057688e7d | |||
12ae2d0c76 | |||
9d91d5a127 | |||
6015f0887a | |||
d4c473d7b3 | |||
2f3978deed | |||
34af53a15b | |||
a4eb3d7a0b | |||
5b46dd7293 | |||
acbe000f97 | |||
599071b68b | |||
2bacee919d | |||
50d35e4196 | |||
e321998b85 | |||
340c02b2af | |||
69a295fe57 | |||
64830aae9f | |||
8969b1273f | |||
475faf7943 | |||
45b1d405a6 | |||
f60c8078e4 | |||
6701e49f9a | |||
0efb3c3284 | |||
aaf3cdfdac | |||
e00c261777 | |||
1eafed755d | |||
7f6a08ae50 | |||
9901816fb9 | |||
3cbe6c1e95 | |||
679c99274e | |||
b6fa0f1ff6 | |||
9ff64b95e1 | |||
3a9885abd8 | |||
503210942c | |||
0178e015e3 | |||
7604992c35 | |||
ee9e551788 | |||
22063248ca | |||
e4ce18b35c | |||
532890674e | |||
791a3b67e6 | |||
84b560ef29 | |||
03f081f3f4 | |||
08213ae86e | |||
73abc511a8 | |||
1c943cc259 | |||
af62a89a6b | |||
af7ca5b897 | |||
27356ef747 | |||
b27f80ef87 | |||
b4aa73fc64 | |||
bbf444572b | |||
b3706574de | |||
83062f8bfb | |||
1d7fcfdaa1 | |||
58ab12b4cb | |||
28c649629f | |||
5ec190225d | |||
0e0d404997 | |||
3f16b908ca | |||
54549b261c | |||
8ce07ced9e | |||
37a5144e8f | |||
59fed7dda8 | |||
0a85a2868c | |||
0d493b3250 | |||
74530d4b1e | |||
7548c52e21 | |||
fa49844c64 | |||
3508ae1e0a | |||
f013ee64a2 | |||
af3da7ca6e | |||
cb728f65b3 | |||
af6af190cc | |||
cbcc8455ca | |||
af35fb79fe | |||
0515aaa946 | |||
1d00330e7a | |||
3fa6dcea16 | |||
51425cac4a | |||
7ce61a5d2b | |||
5e5caa979b | |||
a719518f8f | |||
d0e5aef443 | |||
b82a811c33 | |||
3356dcf8f7 | |||
8f1cc26537 | |||
27dafa83ac | |||
c1be1f329f | |||
c757cef549 | |||
da9e4c026c | |||
5821d67e69 | |||
ed14f6d13f | |||
35bdd8b4ef | |||
9cf2d30e77 | |||
a2140a3b7b | |||
900d026bcb | |||
68604ec15a | |||
f7c0ebb8d3 | |||
8be5d0c72d | |||
15c8b724e6 | |||
d6949200f9 | |||
1c2abe794a | |||
0bcf393586 | |||
bc0573918f | |||
175675ad99 | |||
b00c2afc46 | |||
c125a7fe07 | |||
a42ab32436 | |||
797a64976e | |||
ac377a8b68 | |||
842b7b1402 | |||
d449396ad5 | |||
532a87d064 | |||
e1cdc7b387 | |||
d9d917e267 | |||
8048788042 | |||
790fc88e47 | |||
7f970d489f | |||
9d85ca07f4 | |||
d75e3acdf3 | |||
694cda0e99 | |||
94f134c6a7 | |||
83f329d93c | |||
de49387fca | |||
e5567f2f46 | |||
80f545f3d5 | |||
06f0cc70b8 | |||
cf6b7544b0 | |||
d511c6334a | |||
0224fd6d54 | |||
e95ae8dbcf | |||
5fbd64da71 | |||
b282a2a621 | |||
9a7a534051 | |||
52fd030b6e | |||
dfe530a764 | |||
b079956075 | |||
e30037c4d1 | |||
eda7be627c | |||
af0a649656 | |||
8b6a3c4236 | |||
0988a92d8a | |||
9cf67764b7 | |||
6c4e1d1c41 | |||
b1cd1ea8b3 | |||
5169ed494c | |||
824211c31b | |||
be3dd83bc7 | |||
c2911c1e48 | |||
9a66c5c07d | |||
34d393b986 | |||
d4da02318d | |||
47162af6d5 | |||
8cd6a72dd3 | |||
ba0a183b6f | |||
73781c7edb | |||
6d99852c81 | |||
9325c726fd | |||
947bb8530e | |||
2b32f316ee | |||
4b1f23a189 | |||
71d220e7a4 | |||
747d0d0d17 | |||
5c72e6d335 | |||
e1ac2b0e10 | |||
0ba94f3bc9 | |||
ba0bfafcd5 | |||
81adb80b7e | |||
cb238ef170 | |||
b9b921de82 | |||
d10e31c278 | |||
fd641d77c7 | |||
2aa9710dd1 | |||
4afb2ef2b8 | |||
a54e6e7c4b | |||
7af26a356f | |||
2f66165f8c | |||
e86ce8fc38 | |||
9b48c65129 | |||
434cd133df | |||
aa91e4cdee | |||
d57c1e7ff0 | |||
13e97703e5 | |||
c597b293b8 | |||
6620d64ce7 | |||
2ae120c878 | |||
7a25035fb1 | |||
bf4052b550 | |||
5ca5ad2cee | |||
2848f1e13c | |||
f7895823cb | |||
b841c5c5e5 | |||
a7952a4633 | |||
d047d26dbf | |||
ddedc1640f | |||
021d7e5efc | |||
332e528012 | |||
a0155da06b | |||
d58d22adbe | |||
653352bff0 | |||
4f5b33d8df | |||
7e7d83ac36 | |||
0de5c043bb | |||
ec2769ea3c | |||
3f742f5f8e | |||
50849101d4 | |||
1ccf4a74c9 | |||
7cd4967963 | |||
21e2700da5 | |||
395a68ad80 | |||
b7f0132675 | |||
4ac827b9e8 | |||
d96963862e | |||
53217b061d | |||
4770daa7c6 | |||
2b709ad094 | |||
378b81b13b | |||
56ee72214f | |||
2e7c3167f5 | |||
a2fb728d3b | |||
be1c936e90 | |||
af8037ab03 | |||
3b8dc98226 | |||
b411b4e61b | |||
436eb30490 | |||
09b8087787 | |||
4ac4c69820 | |||
3ebc5c0865 | |||
7b94f8f105 | |||
ec994b3e97 | |||
86ae0182fd | |||
bfa891f0ca | |||
ef843cac63 | |||
78d68d0a4f | |||
4bceba777d | |||
2e537b1e5e | |||
df8463b625 | |||
f40371e0cf | |||
a565e7aed6 | |||
c948361090 | |||
4cf2b74a01 | |||
de9c8362ac | |||
b5bb5d35e7 | |||
d910cfa919 | |||
5857e3d5c6 | |||
25daa343c6 | |||
85224c8f0c | |||
5f8583e3eb | |||
062821d267 | |||
1fdaaf82d2 | |||
e4c1b17810 | |||
70057542c1 | |||
f2255ee707 | |||
791cc70b09 | |||
24dcb9973b | |||
adfd0d5c18 | |||
cfb128acb8 | |||
1e8e246ffb | |||
6162244730 | |||
86cbdf2442 | |||
5334626efb | |||
708d473b47 | |||
ead954ddaa | |||
294f511b9a | |||
b5ebcc3e07 | |||
7b8e7ac5c2 | |||
904d39beac | |||
8958b61fdd | |||
09293f7d9a | |||
d520c3d674 | |||
430e616328 | |||
976ad5fcee | |||
4d58ee2162 |
@ -1,4 +1,5 @@
|
|||||||
using Microsoft.AspNetCore.Components.Authorization;
|
using Microsoft.AspNetCore.Components.Authorization;
|
||||||
|
using Oqtane.Interfaces;
|
||||||
using Oqtane.Providers;
|
using Oqtane.Providers;
|
||||||
using Oqtane.Services;
|
using Oqtane.Services;
|
||||||
using Oqtane.Shared;
|
using Oqtane.Shared;
|
||||||
@ -51,6 +52,10 @@ namespace Microsoft.Extensions.DependencyInjection
|
|||||||
services.AddScoped<IVisitorService, VisitorService>();
|
services.AddScoped<IVisitorService, VisitorService>();
|
||||||
services.AddScoped<ISyncService, SyncService>();
|
services.AddScoped<ISyncService, SyncService>();
|
||||||
|
|
||||||
|
// providers
|
||||||
|
services.AddScoped<ITextEditor, Oqtane.Modules.Controls.QuillJSTextEditor>();
|
||||||
|
services.AddScoped<ITextEditor, Oqtane.Modules.Controls.TextAreaTextEditor>();
|
||||||
|
|
||||||
return services;
|
return services;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -40,10 +40,14 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<br />
|
||||||
<button type="button" class="btn btn-success" @onclick="SaveFile">@SharedLocalizer["Save"]</button>
|
<button type="button" class="btn btn-success" @onclick="SaveFile">@SharedLocalizer["Save"]</button>
|
||||||
<NavLink class="btn btn-secondary" href="@NavigateUrl()">@SharedLocalizer["Cancel"]</NavLink>
|
<NavLink class="btn btn-secondary" href="@NavigateUrl()">@SharedLocalizer["Cancel"]</NavLink>
|
||||||
<br />
|
@if (_name.ToLower().EndsWith(".zip"))
|
||||||
<br />
|
{
|
||||||
|
<button type="button" class="btn btn-primary mx-1" @onclick="UnzipFile">Unzip</button>
|
||||||
|
}
|
||||||
|
<br /><br />
|
||||||
<AuditInfo CreatedBy="@_createdBy" CreatedOn="@_createdOn" ModifiedBy="@_modifiedBy" ModifiedOn="@_modifiedOn"></AuditInfo>
|
<AuditInfo CreatedBy="@_createdBy" CreatedOn="@_createdOn" ModifiedBy="@_modifiedBy" ModifiedOn="@_modifiedOn"></AuditInfo>
|
||||||
</form>
|
</form>
|
||||||
}
|
}
|
||||||
@ -126,4 +130,18 @@
|
|||||||
AddModuleMessage(SharedLocalizer["Message.InfoRequired"], MessageType.Warning);
|
AddModuleMessage(SharedLocalizer["Message.InfoRequired"], MessageType.Warning);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async Task UnzipFile()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await FileService.UnzipFileAsync(_fileId);
|
||||||
|
NavigationManager.NavigateTo(NavigateUrl());
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
await logger.LogError(ex, "Error Unzipping File {FileId} {Error}", _fileId, ex.Message);
|
||||||
|
AddModuleMessage(Localizer["Error.File.Unzip"], MessageType.Error);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
@ -8,6 +8,8 @@
|
|||||||
|
|
||||||
@if (_folders != null)
|
@if (_folders != null)
|
||||||
{
|
{
|
||||||
|
<TabStrip>
|
||||||
|
<TabPanel Name="Settings" ResourceKey="Settings" Heading="Settings">
|
||||||
<form @ref="form" class="@(validated ? "was-validated" : "needs-validation")" novalidate>
|
<form @ref="form" class="@(validated ? "was-validated" : "needs-validation")" novalidate>
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="row mb-1 align-items-center">
|
<div class="row mb-1 align-items-center">
|
||||||
@ -59,16 +61,24 @@
|
|||||||
<input id="capacity" class="form-control" @bind="@_capacity" required />
|
<input id="capacity" class="form-control" @bind="@_capacity" required />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
@if (PageState.QueryString.ContainsKey("id"))
|
||||||
|
{
|
||||||
|
<br />
|
||||||
|
<AuditInfo CreatedBy="@_createdBy" CreatedOn="@_createdOn" ModifiedBy="@_modifiedBy" ModifiedOn="@_modifiedOn"></AuditInfo>
|
||||||
|
}
|
||||||
|
</form>
|
||||||
|
</TabPanel>
|
||||||
|
<TabPanel Name="Permissions" ResourceKey="Permissions" Heading="Permissions">
|
||||||
|
<div class="container">
|
||||||
<div class="row mb-1 align-items-center">
|
<div class="row mb-1 align-items-center">
|
||||||
<div class="col-sm-12">
|
|
||||||
<Label Class="col-sm-3" For="permissions" HelpText="Select the permissions you want for the folder" ResourceKey="Permissions">Permissions: </Label>
|
|
||||||
<PermissionGrid EntityName="@EntityNames.Folder" PermissionNames="@(PermissionNames.Browse + "," + PermissionNames.View + "," + PermissionNames.Edit)" PermissionList="@_permissions" @ref="_permissionGrid" />
|
<PermissionGrid EntityName="@EntityNames.Folder" PermissionNames="@(PermissionNames.Browse + "," + PermissionNames.View + "," + PermissionNames.Edit)" PermissionList="@_permissions" @ref="_permissionGrid" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</TabPanel>
|
||||||
</form>
|
</TabStrip>
|
||||||
<br /><br />
|
|
||||||
|
|
||||||
|
<br />
|
||||||
@if (!_isSystem)
|
@if (!_isSystem)
|
||||||
{
|
{
|
||||||
<button type="button" class="btn btn-success" @onclick="SaveFolder">@SharedLocalizer["Save"]</button>
|
<button type="button" class="btn btn-success" @onclick="SaveFolder">@SharedLocalizer["Save"]</button>
|
||||||
@ -80,11 +90,6 @@
|
|||||||
@((MarkupString)" ")
|
@((MarkupString)" ")
|
||||||
<ActionDialog Header="Delete Folder" Message="Are You Sure You Wish To Delete This Folder?" Action="Delete" Security="SecurityAccessLevel.Admin" Class="btn btn-danger" OnClick="@(async () => await DeleteFolder())" ResourceKey="DeleteFolder" />
|
<ActionDialog Header="Delete Folder" Message="Are You Sure You Wish To Delete This Folder?" Action="Delete" Security="SecurityAccessLevel.Admin" Class="btn btn-danger" OnClick="@(async () => await DeleteFolder())" ResourceKey="DeleteFolder" />
|
||||||
}
|
}
|
||||||
<br /><br />
|
|
||||||
@if (PageState.QueryString.ContainsKey("id"))
|
|
||||||
{
|
|
||||||
<AuditInfo CreatedBy="@_createdBy" CreatedOn="@_createdOn" ModifiedBy="@_modifiedBy" ModifiedOn="@_modifiedOn"></AuditInfo>
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@code {
|
@code {
|
||||||
@ -170,6 +175,7 @@
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
Folder folder;
|
Folder folder;
|
||||||
|
|
||||||
if (_folderId != -1)
|
if (_folderId != -1)
|
||||||
{
|
{
|
||||||
folder = await FolderService.GetFolderAsync(_folderId);
|
folder = await FolderService.GetFolderAsync(_folderId);
|
||||||
@ -179,8 +185,6 @@
|
|||||||
folder = new Folder();
|
folder = new Folder();
|
||||||
}
|
}
|
||||||
|
|
||||||
folder.SiteId = PageState.Site.SiteId;
|
|
||||||
|
|
||||||
if (_parentId == -1)
|
if (_parentId == -1)
|
||||||
{
|
{
|
||||||
folder.ParentId = null;
|
folder.ParentId = null;
|
||||||
@ -190,6 +194,14 @@
|
|||||||
folder.ParentId = _parentId;
|
folder.ParentId = _parentId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// check for duplicate folder names
|
||||||
|
if (_folders.Any(item => item.ParentId == folder.ParentId && item.Name == _name && item.FolderId != _folderId))
|
||||||
|
{
|
||||||
|
AddModuleMessage(Localizer["Message.Folder.Duplicate"], MessageType.Warning);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
folder.SiteId = PageState.Site.SiteId;
|
||||||
folder.Name = _name;
|
folder.Name = _name;
|
||||||
folder.Type = _type;
|
folder.Type = _type;
|
||||||
folder.ImageSizes = _imagesizes;
|
folder.ImageSizes = _imagesizes;
|
||||||
|
19
Oqtane.Client/Modules/Admin/Files/ModuleInfo.cs
Normal file
19
Oqtane.Client/Modules/Admin/Files/ModuleInfo.cs
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
using Oqtane.Documentation;
|
||||||
|
using Oqtane.Models;
|
||||||
|
using Oqtane.Shared;
|
||||||
|
|
||||||
|
namespace Oqtane.Modules.Admin.Files
|
||||||
|
{
|
||||||
|
[PrivateApi("Mark this as private, since it's not very useful in the public docs")]
|
||||||
|
public class ModuleInfo : IModule
|
||||||
|
{
|
||||||
|
public ModuleDefinition ModuleDefinition => new ModuleDefinition
|
||||||
|
{
|
||||||
|
Name = "File Management",
|
||||||
|
Description = "File Management",
|
||||||
|
Version = Constants.Version,
|
||||||
|
Categories = "Admin",
|
||||||
|
ServerManagerType = "Oqtane.Modules.Admin.Files.Manager.FileManager, Oqtane.Server"
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
@ -10,9 +10,7 @@
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
<ActionLink Action="Log" Class="btn btn-secondary" Text="View Logs" ResourceKey="ViewJobs" />
|
<button type="button" class="btn btn-secondary" @onclick="Refresh">@Localizer["Refresh.Text"]</button>
|
||||||
<button type="button" class="btn btn-secondary" @onclick="(async () => await Refresh())">@Localizer["Refresh.Text"]</button>
|
|
||||||
<br />
|
|
||||||
<br />
|
<br />
|
||||||
|
|
||||||
<Pager Items="@_jobs" SearchProperties="Name">
|
<Pager Items="@_jobs" SearchProperties="Name">
|
||||||
@ -26,8 +24,8 @@ else
|
|||||||
<th style="width: 1px;"> </th>
|
<th style="width: 1px;"> </th>
|
||||||
</Header>
|
</Header>
|
||||||
<Row>
|
<Row>
|
||||||
<td><ActionLink Action="Edit" Parameters="@($"id=" + context.JobId.ToString())" ResourceKey="EditJob" /></td>
|
<td><ActionLink Action="Edit" Text="Edit" Parameters="@($"id=" + context.JobId.ToString())" ResourceKey="EditJob" /></td>
|
||||||
<td><ActionLink Action="Log" Class="btn btn-secondary" Parameters="@($"id=" + context.JobId.ToString())" ResourceKey="JobLog" /></td>
|
<td><ActionLink Action="Log" Text="Log" Class="btn btn-secondary" Parameters="@($"id=" + context.JobId.ToString())" ResourceKey="JobLog" /></td>
|
||||||
<td>@context.Name</td>
|
<td>@context.Name</td>
|
||||||
<td>@DisplayStatus(context.IsEnabled, context.IsExecuting)</td>
|
<td>@DisplayStatus(context.IsEnabled, context.IsExecuting)</td>
|
||||||
<td>@DisplayFrequency(context.Interval, context.Frequency)</td>
|
<td>@DisplayFrequency(context.Interval, context.Frequency)</td>
|
||||||
@ -44,6 +42,9 @@ else
|
|||||||
</td>
|
</td>
|
||||||
</Row>
|
</Row>
|
||||||
</Pager>
|
</Pager>
|
||||||
|
|
||||||
|
<br />
|
||||||
|
<ActionLink Action="Log" Class="btn btn-secondary" Text="View All Logs" ResourceKey="ViewLogs" />
|
||||||
}
|
}
|
||||||
|
|
||||||
@code {
|
@code {
|
||||||
@ -53,13 +54,18 @@ else
|
|||||||
|
|
||||||
protected override async Task OnInitializedAsync()
|
protected override async Task OnInitializedAsync()
|
||||||
{
|
{
|
||||||
_jobs = await JobService.GetJobsAsync();
|
await GetJobs();
|
||||||
if (_jobs.Count == 0)
|
if (_jobs.Count == 0)
|
||||||
{
|
{
|
||||||
AddModuleMessage(string.Format(Localizer["Message.NoJobs"], NavigateUrl("admin/system")), MessageType.Warning);
|
AddModuleMessage(string.Format(Localizer["Message.NoJobs"], NavigateUrl("admin/system")), MessageType.Warning);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async Task GetJobs()
|
||||||
|
{
|
||||||
|
_jobs = await JobService.GetJobsAsync();
|
||||||
|
}
|
||||||
|
|
||||||
private string DisplayStatus(bool isEnabled, bool isExecuting)
|
private string DisplayStatus(bool isEnabled, bool isExecuting)
|
||||||
{
|
{
|
||||||
var status = string.Empty;
|
var status = string.Empty;
|
||||||
@ -146,7 +152,8 @@ else
|
|||||||
|
|
||||||
private async Task Refresh()
|
private async Task Refresh()
|
||||||
{
|
{
|
||||||
_jobs = await JobService.GetJobsAsync();
|
ShowProgressIndicator();
|
||||||
StateHasChanged();
|
await GetJobs();
|
||||||
|
HideProgressIndicator();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -10,6 +10,9 @@
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
<button type="button" class="btn btn-secondary" @onclick="Refresh">@Localizer["Refresh"]</button>
|
||||||
|
<br /><br />
|
||||||
|
|
||||||
<Pager Items="@_jobLogs">
|
<Pager Items="@_jobLogs">
|
||||||
<Header>
|
<Header>
|
||||||
<th>@SharedLocalizer["Name"]</th>
|
<th>@SharedLocalizer["Name"]</th>
|
||||||
@ -35,6 +38,11 @@ else
|
|||||||
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Host;
|
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Host;
|
||||||
|
|
||||||
protected override async Task OnParametersSetAsync()
|
protected override async Task OnParametersSetAsync()
|
||||||
|
{
|
||||||
|
await GetJobLogs();
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task GetJobLogs()
|
||||||
{
|
{
|
||||||
_jobLogs = await JobLogService.GetJobLogsAsync();
|
_jobLogs = await JobLogService.GetJobLogsAsync();
|
||||||
|
|
||||||
@ -67,4 +75,11 @@ else
|
|||||||
|
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async Task Refresh()
|
||||||
|
{
|
||||||
|
ShowProgressIndicator();
|
||||||
|
await GetJobLogs();
|
||||||
|
HideProgressIndicator();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -93,6 +93,7 @@
|
|||||||
private string _code = string.Empty;
|
private string _code = string.Empty;
|
||||||
|
|
||||||
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Anonymous;
|
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Anonymous;
|
||||||
|
public override bool? Prerender => true;
|
||||||
|
|
||||||
public override List<Resource> Resources => new List<Resource>()
|
public override List<Resource> Resources => new List<Resource>()
|
||||||
{
|
{
|
||||||
@ -207,17 +208,20 @@
|
|||||||
{
|
{
|
||||||
await logger.LogInformation(LogFunction.Security, "Login Successful For Username {Username}", _username);
|
await logger.LogInformation(LogFunction.Security, "Login Successful For Username {Username}", _username);
|
||||||
|
|
||||||
|
// return url is not specified if user navigated directly to login page
|
||||||
|
var returnurl = (!string.IsNullOrEmpty(PageState.ReturnUrl)) ? PageState.ReturnUrl : PageState.Alias.Path;
|
||||||
|
|
||||||
if (hybrid)
|
if (hybrid)
|
||||||
{
|
{
|
||||||
// hybrid apps utilize an interactive login
|
// hybrid apps utilize an interactive login
|
||||||
var authstateprovider = (IdentityAuthenticationStateProvider)ServiceProvider.GetService(typeof(IdentityAuthenticationStateProvider));
|
var authstateprovider = (IdentityAuthenticationStateProvider)ServiceProvider.GetService(typeof(IdentityAuthenticationStateProvider));
|
||||||
authstateprovider.NotifyAuthenticationChanged();
|
authstateprovider.NotifyAuthenticationChanged();
|
||||||
NavigationManager.NavigateTo(NavigateUrl(PageState.ReturnUrl, true));
|
NavigationManager.NavigateTo(NavigateUrl(returnurl, true));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// post back to the Login page so that the cookies are set correctly
|
// post back to the Login page so that the cookies are set correctly
|
||||||
var fields = new { __RequestVerificationToken = SiteState.AntiForgeryToken, username = _username, password = _password, remember = _remember, returnurl = WebUtility.UrlEncode(PageState.ReturnUrl) };
|
var fields = new { __RequestVerificationToken = SiteState.AntiForgeryToken, username = _username, password = _password, remember = _remember, returnurl = WebUtility.UrlEncode(returnurl) };
|
||||||
string url = Utilities.TenantUrl(PageState.Alias, "/pages/login/");
|
string url = Utilities.TenantUrl(PageState.Alias, "/pages/login/");
|
||||||
await interop.SubmitForm(url, fields);
|
await interop.SubmitForm(url, fields);
|
||||||
}
|
}
|
||||||
|
@ -63,7 +63,7 @@ else
|
|||||||
<th>@Localizer["Function"]</th>
|
<th>@Localizer["Function"]</th>
|
||||||
</Header>
|
</Header>
|
||||||
<Row>
|
<Row>
|
||||||
<td class="@GetClass(context.Function)"><ActionLink Action="Detail" Parameters="@($"/{context.LogId}")" ReturnUrl="@(NavigateUrl(PageState.Page.Path, AddUrlParameters(_level, _function, _rows, _page)))" ResourceKey="LogDetails" /></td>
|
<td class="@GetClass(context.Function)"><ActionLink Action="Detail" Text="Details" Parameters="@($"/{context.LogId}")" ReturnUrl="@(NavigateUrl(PageState.Page.Path, AddUrlParameters(_level, _function, _rows, _page)))" ResourceKey="LogDetails" /></td>
|
||||||
<td class="@GetClass(context.Function)">@context.LogDate</td>
|
<td class="@GetClass(context.Function)">@context.LogDate</td>
|
||||||
<td class="@GetClass(context.Function)">@context.Level</td>
|
<td class="@GetClass(context.Function)">@context.Level</td>
|
||||||
<td class="@GetClass(context.Function)">@context.Feature</td>
|
<td class="@GetClass(context.Function)">@context.Feature</td>
|
||||||
|
@ -125,7 +125,7 @@
|
|||||||
<TabPanel Name="Upload" ResourceKey="Upload" Heading="Upload">
|
<TabPanel Name="Upload" ResourceKey="Upload" Heading="Upload">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="row mb-1 align-items-center">
|
<div class="row mb-1 align-items-center">
|
||||||
<Label Class="col-sm-3" HelpText="Upload one or more module packages. Once they are uploaded click Install to complete the installation." ResourceKey="Module">Module: </Label>
|
<Label Class="col-sm-3" HelpText="Upload one or more module packages." ResourceKey="Module">Module: </Label>
|
||||||
<div class="col-sm-9">
|
<div class="col-sm-9">
|
||||||
<FileManager Folder="@Constants.PackagesFolder" UploadMultiple="true" OnUpload="OnUpload" />
|
<FileManager Folder="@Constants.PackagesFolder" UploadMultiple="true" OnUpload="OnUpload" />
|
||||||
</div>
|
</div>
|
||||||
|
@ -10,6 +10,7 @@
|
|||||||
@inject IStringLocalizer<SharedResources> SharedLocalizer
|
@inject IStringLocalizer<SharedResources> SharedLocalizer
|
||||||
@inject IPageModuleService PageModuleService
|
@inject IPageModuleService PageModuleService
|
||||||
@inject IModuleService ModuleService
|
@inject IModuleService ModuleService
|
||||||
|
@inject IPageService PageService
|
||||||
|
|
||||||
@if (_initialized)
|
@if (_initialized)
|
||||||
{
|
{
|
||||||
@ -32,7 +33,7 @@
|
|||||||
<div class="row mb-1 align-items-center">
|
<div class="row mb-1 align-items-center">
|
||||||
<Label Class="col-sm-3" For="categories" HelpText="Comma delimited list of module categories" ResourceKey="Categories">Categories: </Label>
|
<Label Class="col-sm-3" For="categories" HelpText="Comma delimited list of module categories" ResourceKey="Categories">Categories: </Label>
|
||||||
<div class="col-sm-9">
|
<div class="col-sm-9">
|
||||||
<input id="categories" class="form-control" @bind="@_categories" maxlength="200" required />
|
<input id="categories" class="form-control" @bind="@_categories" maxlength="200" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row mb-1 align-items-center">
|
<div class="row mb-1 align-items-center">
|
||||||
@ -306,15 +307,16 @@
|
|||||||
_languages = _languages.OrderBy(item => item.Name).ToList();
|
_languages = _languages.OrderBy(item => item.Name).ToList();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Group modules by PageId
|
// get distinct pages where module exists
|
||||||
// Get distinct PageIds where modules are present
|
var modules = await ModuleService.GetModulesAsync(PageState.Site.SiteId);
|
||||||
var distinctPageIds = PageState.Modules
|
var distinctPageIds = modules
|
||||||
.Where(md => md.ModuleDefinition.ModuleDefinitionId == _moduleDefinitionId && md.IsDeleted == false)
|
.Where(md => md.ModuleDefinition?.ModuleDefinitionId == _moduleDefinitionId && md.IsDeleted == false)
|
||||||
.Select(md => md.PageId)
|
.Select(md => md.PageId)
|
||||||
.Distinct();
|
.Distinct();
|
||||||
|
|
||||||
// Filter and retrieve the corresponding pages
|
// retrieve the pages which contain the module
|
||||||
_pagesWithModules = PageState.Pages
|
var pages = await PageService.GetPagesAsync(PageState.Site.SiteId);
|
||||||
|
_pagesWithModules = pages
|
||||||
.Where(pg => distinctPageIds.Contains(pg.PageId) && pg.IsDeleted == false)
|
.Where(pg => distinctPageIds.Contains(pg.PageId) && pg.IsDeleted == false)
|
||||||
.ToList();
|
.ToList();
|
||||||
|
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
@namespace Oqtane.Modules.Admin.ModuleDefinitions
|
@namespace Oqtane.Modules.Admin.ModuleDefinitions
|
||||||
@inherits ModuleBase
|
@inherits ModuleBase
|
||||||
@inject NavigationManager NavigationManager
|
@inject NavigationManager NavigationManager
|
||||||
|
@inject IModuleService ModuleService
|
||||||
@inject IModuleDefinitionService ModuleDefinitionService
|
@inject IModuleDefinitionService ModuleDefinitionService
|
||||||
@inject IPackageService PackageService
|
@inject IPackageService PackageService
|
||||||
@inject IStringLocalizer<Index> Localizer
|
@inject IStringLocalizer<Index> Localizer
|
||||||
@ -50,7 +51,7 @@ else
|
|||||||
<th style="width: 1px;"> </th>
|
<th style="width: 1px;"> </th>
|
||||||
</Header>
|
</Header>
|
||||||
<Row>
|
<Row>
|
||||||
<td><ActionLink Action="Edit" Parameters="@($"id=" + context.ModuleDefinitionId.ToString())" ResourceKey="EditModule" /></td>
|
<td><ActionLink Action="Edit" Text="Edit" Parameters="@($"id=" + context.ModuleDefinitionId.ToString())" ResourceKey="EditModule" /></td>
|
||||||
<td>
|
<td>
|
||||||
@if (context.AssemblyName != Constants.ClientId)
|
@if (context.AssemblyName != Constants.ClientId)
|
||||||
{
|
{
|
||||||
@ -70,7 +71,7 @@ else
|
|||||||
}
|
}
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
@if (context.AssemblyName == Constants.ClientId || PageState.Modules.Where(m => m.ModuleDefinition?.ModuleDefinitionId == context.ModuleDefinitionId).FirstOrDefault() != null)
|
@if (context.AssemblyName == Constants.ClientId || _modules.Where(m => m.ModuleDefinition?.ModuleDefinitionId == context.ModuleDefinitionId).FirstOrDefault() != null)
|
||||||
{
|
{
|
||||||
<span>@SharedLocalizer["Yes"]</span>
|
<span>@SharedLocalizer["Yes"]</span>
|
||||||
}
|
}
|
||||||
@ -99,6 +100,7 @@ else
|
|||||||
}
|
}
|
||||||
|
|
||||||
@code {
|
@code {
|
||||||
|
private List<Module> _modules;
|
||||||
private List<ModuleDefinition> _allModuleDefinitions;
|
private List<ModuleDefinition> _allModuleDefinitions;
|
||||||
private List<ModuleDefinition> _moduleDefinitions;
|
private List<ModuleDefinition> _moduleDefinitions;
|
||||||
private List<Package> _packages;
|
private List<Package> _packages;
|
||||||
@ -111,6 +113,7 @@ else
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
_modules = await ModuleService.GetModulesAsync(PageState.Site.SiteId);
|
||||||
_allModuleDefinitions = await ModuleDefinitionService.GetModuleDefinitionsAsync(PageState.Site.SiteId);
|
_allModuleDefinitions = await ModuleDefinitionService.GetModuleDefinitionsAsync(PageState.Site.SiteId);
|
||||||
_categories = _allModuleDefinitions.SelectMany(m => m.Categories.Split(',')).Distinct().ToList();
|
_categories = _allModuleDefinitions.SelectMany(m => m.Categories.Split(',')).Distinct().ToList();
|
||||||
await LoadModuleDefinitions();
|
await LoadModuleDefinitions();
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
@inherits ModuleBase
|
@inherits ModuleBase
|
||||||
@inject NavigationManager NavigationManager
|
@inject NavigationManager NavigationManager
|
||||||
@inject IThemeService ThemeService
|
@inject IThemeService ThemeService
|
||||||
|
@inject IPageService PageService
|
||||||
@inject IModuleService ModuleService
|
@inject IModuleService ModuleService
|
||||||
@inject IPageModuleService PageModuleService
|
@inject IPageModuleService PageModuleService
|
||||||
@inject IStringLocalizer<Settings> Localizer
|
@inject IStringLocalizer<Settings> Localizer
|
||||||
@ -79,14 +80,16 @@
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
foreach (Page p in PageState.Pages)
|
if (_pages != null)
|
||||||
|
{
|
||||||
|
foreach (Page p in _pages)
|
||||||
{
|
{
|
||||||
if (UserSecurity.IsAuthorized(PageState.User, PermissionNames.Edit, p.PermissionList))
|
if (UserSecurity.IsAuthorized(PageState.User, PermissionNames.Edit, p.PermissionList))
|
||||||
{
|
{
|
||||||
<option value="@p.PageId">@(new string('-', p.Level * 2))@(p.Name)</option>
|
<option value="@p.PageId">@(new string('-', p.Level * 2))@(p.Name)</option>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
@ -94,7 +97,7 @@
|
|||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
</TabPanel>
|
</TabPanel>
|
||||||
<TabPanel Name="Permissions" ResourceKey="Permissions">
|
<TabPanel Name="Permissions" Heading="Permissions" ResourceKey="Permissions">
|
||||||
@if (_permissions != null)
|
@if (_permissions != null)
|
||||||
{
|
{
|
||||||
<div class="container">
|
<div class="container">
|
||||||
@ -126,9 +129,8 @@
|
|||||||
<AuditInfo CreatedBy="@createdby" CreatedOn="@createdon" ModifiedBy="@modifiedby" ModifiedOn="@modifiedon"></AuditInfo>
|
<AuditInfo CreatedBy="@createdby" CreatedOn="@createdon" ModifiedBy="@modifiedby" ModifiedOn="@modifiedon"></AuditInfo>
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
@code {
|
@code {
|
||||||
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Edit;
|
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Edit;
|
||||||
public override string Title => "Module Settings";
|
|
||||||
|
|
||||||
private ElementReference form;
|
private ElementReference form;
|
||||||
private bool validated = false;
|
private bool validated = false;
|
||||||
@ -144,7 +146,7 @@
|
|||||||
private PermissionGrid _permissionGrid;
|
private PermissionGrid _permissionGrid;
|
||||||
private Type _moduleSettingsType;
|
private Type _moduleSettingsType;
|
||||||
private object _moduleSettings;
|
private object _moduleSettings;
|
||||||
private string _moduleSettingsTitle = "Module Settings";
|
private string _moduleSettingsTitle;
|
||||||
private RenderFragment ModuleSettingsComponent { get; set; }
|
private RenderFragment ModuleSettingsComponent { get; set; }
|
||||||
private Type _containerSettingsType;
|
private Type _containerSettingsType;
|
||||||
private object _containerSettings;
|
private object _containerSettings;
|
||||||
@ -155,11 +157,15 @@
|
|||||||
private DateTime modifiedon;
|
private DateTime modifiedon;
|
||||||
private DateTime? _effectivedate = null;
|
private DateTime? _effectivedate = null;
|
||||||
private DateTime? _expirydate = null;
|
private DateTime? _expirydate = null;
|
||||||
|
private List<Page> _pages;
|
||||||
|
|
||||||
protected override void OnInitialized()
|
protected override async Task OnInitializedAsync()
|
||||||
{
|
{
|
||||||
|
SetModuleTitle(Localizer["ModuleSettings.Title"]);
|
||||||
|
|
||||||
_module = ModuleState.ModuleDefinition.Name;
|
_module = ModuleState.ModuleDefinition.Name;
|
||||||
_title = ModuleState.Title;
|
_title = ModuleState.Title;
|
||||||
|
_moduleSettingsTitle = Localizer["ModuleSettings.Heading"];
|
||||||
_pane = ModuleState.Pane;
|
_pane = ModuleState.Pane;
|
||||||
_containers = ThemeService.GetContainerControls(PageState.Site.Themes, PageState.Page.ThemeType);
|
_containers = ThemeService.GetContainerControls(PageState.Site.Themes, PageState.Page.ThemeType);
|
||||||
_containerType = ModuleState.ContainerType;
|
_containerType = ModuleState.ContainerType;
|
||||||
@ -172,6 +178,7 @@
|
|||||||
modifiedon = ModuleState.ModifiedOn;
|
modifiedon = ModuleState.ModifiedOn;
|
||||||
_effectivedate = Utilities.UtcAsLocalDate(ModuleState.EffectiveDate);
|
_effectivedate = Utilities.UtcAsLocalDate(ModuleState.EffectiveDate);
|
||||||
_expirydate = Utilities.UtcAsLocalDate(ModuleState.ExpiryDate);
|
_expirydate = Utilities.UtcAsLocalDate(ModuleState.ExpiryDate);
|
||||||
|
_pages = await PageService.GetPagesAsync(PageState.Site.SiteId);
|
||||||
|
|
||||||
if (ModuleState.ModuleDefinition != null)
|
if (ModuleState.ModuleDefinition != null)
|
||||||
{
|
{
|
||||||
|
@ -26,7 +26,7 @@
|
|||||||
<div class="col-sm-9">
|
<div class="col-sm-9">
|
||||||
<select id="parent" class="form-select" value="@_parentid" @onchange="(e => ParentChanged(e))" required>
|
<select id="parent" class="form-select" value="@_parentid" @onchange="(e => ParentChanged(e))" required>
|
||||||
<option value="-1"><@Localizer["SiteRoot"]></option>
|
<option value="-1"><@Localizer["SiteRoot"]></option>
|
||||||
@foreach (Page page in PageState.Pages)
|
@foreach (Page page in _pages)
|
||||||
{
|
{
|
||||||
if (UserSecurity.IsAuthorized(PageState.User, PermissionNames.View, page.PermissionList))
|
if (UserSecurity.IsAuthorized(PageState.User, PermissionNames.View, page.PermissionList))
|
||||||
{
|
{
|
||||||
@ -198,12 +198,6 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</TabPanel>
|
</TabPanel>
|
||||||
@if (_themeSettingsType != null)
|
|
||||||
{
|
|
||||||
<TabPanel Name="ThemeSettings" Heading=@Localizer["Theme.Heading"] ResourceKey="ThemeSettings">
|
|
||||||
@_themeSettingsComponent
|
|
||||||
</TabPanel>
|
|
||||||
}
|
|
||||||
</TabStrip>
|
</TabStrip>
|
||||||
<br />
|
<br />
|
||||||
<button type="button" class="btn btn-success" @onclick="SavePage">@SharedLocalizer["Save"]</button>
|
<button type="button" class="btn btn-success" @onclick="SavePage">@SharedLocalizer["Save"]</button>
|
||||||
@ -219,6 +213,7 @@
|
|||||||
private bool validated = false;
|
private bool validated = false;
|
||||||
private List<ThemeControl> _themes = new List<ThemeControl>();
|
private List<ThemeControl> _themes = new List<ThemeControl>();
|
||||||
private List<ThemeControl> _containers = new List<ThemeControl>();
|
private List<ThemeControl> _containers = new List<ThemeControl>();
|
||||||
|
private List<Page> _pages;
|
||||||
private int _pageId;
|
private int _pageId;
|
||||||
private string _name;
|
private string _name;
|
||||||
private string _parentid = "-1";
|
private string _parentid = "-1";
|
||||||
@ -238,9 +233,6 @@
|
|||||||
private string _bodycontent;
|
private string _bodycontent;
|
||||||
private string _permissions = null;
|
private string _permissions = null;
|
||||||
private PermissionGrid _permissionGrid;
|
private PermissionGrid _permissionGrid;
|
||||||
private Type _themeSettingsType;
|
|
||||||
private object _themeSettings;
|
|
||||||
private RenderFragment _themeSettingsComponent { get; set; }
|
|
||||||
private bool _refresh = false;
|
private bool _refresh = false;
|
||||||
protected Page _parent = null;
|
protected Page _parent = null;
|
||||||
protected Dictionary<string, string> _icons;
|
protected Dictionary<string, string> _icons;
|
||||||
@ -252,6 +244,8 @@
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
_pages = await PageService.GetPagesAsync(PageState.Site.SiteId);
|
||||||
|
|
||||||
if (PageState.QueryString.ContainsKey("id"))
|
if (PageState.QueryString.ContainsKey("id"))
|
||||||
{
|
{
|
||||||
_pageId = Int32.Parse(PageState.QueryString["id"]);
|
_pageId = Int32.Parse(PageState.QueryString["id"]);
|
||||||
@ -272,7 +266,7 @@
|
|||||||
_containers = ThemeService.GetContainerControls(PageState.Site.Themes, _themetype);
|
_containers = ThemeService.GetContainerControls(PageState.Site.Themes, _themetype);
|
||||||
_containertype = PageState.Site.DefaultContainerType;
|
_containertype = PageState.Site.DefaultContainerType;
|
||||||
_children = new List<Page>();
|
_children = new List<Page>();
|
||||||
foreach (Page p in PageState.Pages.Where(item => (_parentid == "-1" && item.ParentId == null) || (item.ParentId == int.Parse(_parentid))))
|
foreach (Page p in _pages.Where(item => (_parentid == "-1" && item.ParentId == null) || (item.ParentId == int.Parse(_parentid))))
|
||||||
{
|
{
|
||||||
if (UserSecurity.IsAuthorized(PageState.User, PermissionNames.View, p.PermissionList))
|
if (UserSecurity.IsAuthorized(PageState.User, PermissionNames.View, p.PermissionList))
|
||||||
{
|
{
|
||||||
@ -281,7 +275,6 @@
|
|||||||
}
|
}
|
||||||
_effectivedate = Utilities.UtcAsLocalDate(PageState.Page.EffectiveDate);
|
_effectivedate = Utilities.UtcAsLocalDate(PageState.Page.EffectiveDate);
|
||||||
_expirydate = Utilities.UtcAsLocalDate(PageState.Page.ExpiryDate);
|
_expirydate = Utilities.UtcAsLocalDate(PageState.Page.ExpiryDate);
|
||||||
ThemeSettings();
|
|
||||||
_initialized = true;
|
_initialized = true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -303,7 +296,7 @@
|
|||||||
{
|
{
|
||||||
_parentid = (string)e.Value;
|
_parentid = (string)e.Value;
|
||||||
_children = new List<Page>();
|
_children = new List<Page>();
|
||||||
foreach (Page p in PageState.Pages.Where(item => (_parentid == "-1" && item.ParentId == null) || (item.ParentId == int.Parse(_parentid))))
|
foreach (Page p in _pages.Where(item => (_parentid == "-1" && item.ParentId == null) || (item.ParentId == int.Parse(_parentid))))
|
||||||
{
|
{
|
||||||
if (UserSecurity.IsAuthorized(PageState.User, PermissionNames.View, p.PermissionList))
|
if (UserSecurity.IsAuthorized(PageState.User, PermissionNames.View, p.PermissionList))
|
||||||
{
|
{
|
||||||
@ -324,7 +317,6 @@
|
|||||||
_themetype = (string)e.Value;
|
_themetype = (string)e.Value;
|
||||||
_containers = ThemeService.GetContainerControls(PageState.Site.Themes, _themetype);
|
_containers = ThemeService.GetContainerControls(PageState.Site.Themes, _themetype);
|
||||||
_containertype = _containers.First().TypeName;
|
_containertype = _containers.First().TypeName;
|
||||||
ThemeSettings();
|
|
||||||
StateHasChanged();
|
StateHasChanged();
|
||||||
|
|
||||||
// if theme chosen is different than default site theme, display warning message to user
|
// if theme chosen is different than default site theme, display warning message to user
|
||||||
@ -334,28 +326,6 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ThemeSettings()
|
|
||||||
{
|
|
||||||
_themeSettingsType = null;
|
|
||||||
_themeSettingsComponent = null;
|
|
||||||
var theme = PageState.Site.Themes.FirstOrDefault(item => item.Themes.Any(themecontrol => themecontrol.TypeName.Equals(_themetype)));
|
|
||||||
if (theme != null && !string.IsNullOrEmpty(theme.ThemeSettingsType))
|
|
||||||
{
|
|
||||||
_themeSettingsType = Type.GetType(theme.ThemeSettingsType);
|
|
||||||
if (_themeSettingsType != null)
|
|
||||||
{
|
|
||||||
_themeSettingsComponent = builder =>
|
|
||||||
{
|
|
||||||
builder.OpenComponent(0, _themeSettingsType);
|
|
||||||
builder.AddAttribute(1, "RenderModeBoundary", RenderModeBoundary);
|
|
||||||
builder.AddComponentReferenceCapture(2, inst => { _themeSettings = Convert.ChangeType(inst, _themeSettingsType); });
|
|
||||||
builder.CloseComponent();
|
|
||||||
};
|
|
||||||
}
|
|
||||||
_refresh = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task SavePage()
|
private async Task SavePage()
|
||||||
{
|
{
|
||||||
validated = true;
|
validated = true;
|
||||||
@ -404,7 +374,7 @@
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Page parent = PageState.Pages.FirstOrDefault(item => item.PageId == page.ParentId);
|
Page parent = _pages.FirstOrDefault(item => item.PageId == page.ParentId);
|
||||||
if (parent.Path == string.Empty)
|
if (parent.Path == string.Empty)
|
||||||
{
|
{
|
||||||
page.Path = Utilities.GetFriendlyUrl(parent.Name) + "/" + Utilities.GetFriendlyUrl(_path);
|
page.Path = Utilities.GetFriendlyUrl(parent.Name) + "/" + Utilities.GetFriendlyUrl(_path);
|
||||||
@ -415,7 +385,6 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var _pages = await PageService.GetPagesAsync(PageState.Site.SiteId);
|
|
||||||
if (_pages.Any(item => item.Path == page.Path))
|
if (_pages.Any(item => item.Path == page.Path))
|
||||||
{
|
{
|
||||||
AddModuleMessage(string.Format(Localizer["Message.Page.Exists"], _path), MessageType.Warning);
|
AddModuleMessage(string.Format(Localizer["Message.Page.Exists"], _path), MessageType.Warning);
|
||||||
@ -435,11 +404,11 @@
|
|||||||
page.Order = 0;
|
page.Order = 0;
|
||||||
break;
|
break;
|
||||||
case "<":
|
case "<":
|
||||||
child = PageState.Pages.Where(item => item.PageId == _childid).FirstOrDefault();
|
child = _pages.Where(item => item.PageId == _childid).FirstOrDefault();
|
||||||
page.Order = child.Order - 1;
|
page.Order = child.Order - 1;
|
||||||
break;
|
break;
|
||||||
case ">":
|
case ">":
|
||||||
child = PageState.Pages.Where(item => item.PageId == _childid).FirstOrDefault();
|
child = _pages.Where(item => item.PageId == _childid).FirstOrDefault();
|
||||||
page.Order = child.Order + 1;
|
page.Order = child.Order + 1;
|
||||||
break;
|
break;
|
||||||
case ">>":
|
case ">>":
|
||||||
@ -482,11 +451,11 @@
|
|||||||
await logger.LogInformation("Page Added {Page}", page);
|
await logger.LogInformation("Page Added {Page}", page);
|
||||||
if (!string.IsNullOrEmpty(PageState.ReturnUrl))
|
if (!string.IsNullOrEmpty(PageState.ReturnUrl))
|
||||||
{
|
{
|
||||||
NavigationManager.NavigateTo(PageState.ReturnUrl, true);
|
NavigationManager.NavigateTo(NavigateUrl(page.Path), true); // redirect to page added and reload
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
NavigationManager.NavigateTo(page.Path); // redirect to new page created
|
NavigationManager.NavigateTo(NavigateUrl()); // redirect to page management
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -1,9 +1,11 @@
|
|||||||
@namespace Oqtane.Modules.Admin.Pages
|
@namespace Oqtane.Modules.Admin.Pages
|
||||||
@using Oqtane.Interfaces
|
@using Oqtane.Interfaces
|
||||||
|
@using System.Globalization
|
||||||
@inherits ModuleBase
|
@inherits ModuleBase
|
||||||
@inject NavigationManager NavigationManager
|
@inject NavigationManager NavigationManager
|
||||||
@inject IPageService PageService
|
@inject IPageService PageService
|
||||||
@inject IPageModuleService PageModuleService
|
@inject IPageModuleService PageModuleService
|
||||||
|
@inject IModuleService ModuleService
|
||||||
@inject IThemeService ThemeService
|
@inject IThemeService ThemeService
|
||||||
@inject ISystemService SystemService
|
@inject ISystemService SystemService
|
||||||
@inject IStringLocalizer<Edit> Localizer
|
@inject IStringLocalizer<Edit> Localizer
|
||||||
@ -30,7 +32,7 @@
|
|||||||
<div class="col-sm-9">
|
<div class="col-sm-9">
|
||||||
<select id="parent" class="form-select" value="@_parentid" @onchange="(e => ParentChanged(e))" required>
|
<select id="parent" class="form-select" value="@_parentid" @onchange="(e => ParentChanged(e))" required>
|
||||||
<option value="-1"><@Localizer["SiteRoot"]></option>
|
<option value="-1"><@Localizer["SiteRoot"]></option>
|
||||||
@foreach (Page page in PageState.Pages)
|
@foreach (Page page in _pages)
|
||||||
{
|
{
|
||||||
if (UserSecurity.IsAuthorized(PageState.User, PermissionNames.View, page.PermissionList) && page.PageId != _pageId)
|
if (UserSecurity.IsAuthorized(PageState.User, PermissionNames.View, page.PermissionList) && page.PageId != _pageId)
|
||||||
{
|
{
|
||||||
@ -301,6 +303,7 @@
|
|||||||
private bool validated = false;
|
private bool validated = false;
|
||||||
private List<ThemeControl> _themes = new List<ThemeControl>();
|
private List<ThemeControl> _themes = new List<ThemeControl>();
|
||||||
private List<ThemeControl> _containers = new List<ThemeControl>();
|
private List<ThemeControl> _containers = new List<ThemeControl>();
|
||||||
|
private List<Page> _pages;
|
||||||
private int _pageId;
|
private int _pageId;
|
||||||
private string _name;
|
private string _name;
|
||||||
private string _currentparentid;
|
private string _currentparentid;
|
||||||
@ -344,6 +347,7 @@
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
_pages = await PageService.GetPagesAsync(PageState.Site.SiteId);
|
||||||
_pageId = Int32.Parse(PageState.QueryString["id"]);
|
_pageId = Int32.Parse(PageState.QueryString["id"]);
|
||||||
_page = await PageService.GetPageAsync(_pageId);
|
_page = await PageService.GetPageAsync(_pageId);
|
||||||
_icons = await SystemService.GetIconsAsync();
|
_icons = await SystemService.GetIconsAsync();
|
||||||
@ -359,10 +363,10 @@
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
_parentid = _page.ParentId.ToString();
|
_parentid = _page.ParentId.ToString();
|
||||||
_parent = PageState.Pages.FirstOrDefault(item => item.PageId == _page.ParentId);
|
_parent = _pages.FirstOrDefault(item => item.PageId == _page.ParentId);
|
||||||
}
|
}
|
||||||
_children = new List<Page>();
|
_children = new List<Page>();
|
||||||
foreach (Page p in PageState.Pages.Where(item => (_parentid == "-1" && item.ParentId == null) || (item.ParentId == int.Parse(_parentid))))
|
foreach (Page p in _pages.Where(item => (_parentid == "-1" && item.ParentId == null) || (item.ParentId == int.Parse(_parentid, CultureInfo.InvariantCulture))))
|
||||||
{
|
{
|
||||||
if (p.PageId != _pageId && UserSecurity.IsAuthorized(PageState.User, PermissionNames.View, p.PermissionList))
|
if (p.PageId != _pageId && UserSecurity.IsAuthorized(PageState.User, PermissionNames.View, p.PermissionList))
|
||||||
{
|
{
|
||||||
@ -414,7 +418,8 @@
|
|||||||
_permissions = _page.PermissionList;
|
_permissions = _page.PermissionList;
|
||||||
|
|
||||||
// page modules
|
// page modules
|
||||||
_pageModules = PageState.Modules.Where(m => m.PageId == _page.PageId).ToList();
|
var modules = await ModuleService.GetModulesAsync(PageState.Site.SiteId);
|
||||||
|
_pageModules = modules.Where(item => item.PageId == _page.PageId && !item.IsDeleted).ToList();
|
||||||
|
|
||||||
// audit
|
// audit
|
||||||
_createdby = _page.CreatedBy;
|
_createdby = _page.CreatedBy;
|
||||||
@ -446,7 +451,7 @@
|
|||||||
{
|
{
|
||||||
_parentid = (string)e.Value;
|
_parentid = (string)e.Value;
|
||||||
_children = new List<Page>();
|
_children = new List<Page>();
|
||||||
foreach (Page p in PageState.Pages.Where(item => (_parentid == "-1" && item.ParentId == null) || (item.ParentId == int.Parse(_parentid))))
|
foreach (Page p in _pages.Where(item => (_parentid == "-1" && item.ParentId == null) || (item.ParentId == int.Parse(_parentid))))
|
||||||
{
|
{
|
||||||
if (p.PageId != _pageId && UserSecurity.IsAuthorized(PageState.User, PermissionNames.View, p.PermissionList))
|
if (p.PageId != _pageId && UserSecurity.IsAuthorized(PageState.User, PermissionNames.View, p.PermissionList))
|
||||||
{
|
{
|
||||||
@ -548,7 +553,7 @@
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Page parent = PageState.Pages.FirstOrDefault(item => item.PageId == _page.ParentId);
|
Page parent = _pages.FirstOrDefault(item => item.PageId == _page.ParentId);
|
||||||
if (parent.Path == string.Empty)
|
if (parent.Path == string.Empty)
|
||||||
{
|
{
|
||||||
_page.Path = Utilities.GetFriendlyUrl(parent.Name) + "/" + Utilities.GetFriendlyUrl(_path);
|
_page.Path = Utilities.GetFriendlyUrl(parent.Name) + "/" + Utilities.GetFriendlyUrl(_path);
|
||||||
@ -559,7 +564,6 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var _pages = await PageService.GetPagesAsync(PageState.Site.SiteId);
|
|
||||||
if (_pages.Any(item => item.Path == _page.Path && item.PageId != _page.PageId))
|
if (_pages.Any(item => item.Path == _page.Path && item.PageId != _page.PageId))
|
||||||
{
|
{
|
||||||
AddModuleMessage(string.Format(Localizer["Mesage.Page.PathExists"], _path), MessageType.Warning);
|
AddModuleMessage(string.Format(Localizer["Mesage.Page.PathExists"], _path), MessageType.Warning);
|
||||||
@ -581,11 +585,11 @@
|
|||||||
_page.Order = 0;
|
_page.Order = 0;
|
||||||
break;
|
break;
|
||||||
case "<":
|
case "<":
|
||||||
child = PageState.Pages.FirstOrDefault(item => item.PageId == _childid);
|
child = _pages.FirstOrDefault(item => item.PageId == _childid);
|
||||||
if (child != null) _page.Order = child.Order - 1;
|
if (child != null) _page.Order = child.Order - 1;
|
||||||
break;
|
break;
|
||||||
case ">":
|
case ">":
|
||||||
child = PageState.Pages.FirstOrDefault(item => item.PageId == _childid);
|
child = _pages.FirstOrDefault(item => item.PageId == _childid);
|
||||||
if (child != null) _page.Order = child.Order + 1;
|
if (child != null) _page.Order = child.Order + 1;
|
||||||
break;
|
break;
|
||||||
case ">>":
|
case ">>":
|
||||||
@ -643,11 +647,11 @@
|
|||||||
await logger.LogInformation("Page Saved {Page}", _page);
|
await logger.LogInformation("Page Saved {Page}", _page);
|
||||||
if (!string.IsNullOrEmpty(PageState.ReturnUrl))
|
if (!string.IsNullOrEmpty(PageState.ReturnUrl))
|
||||||
{
|
{
|
||||||
NavigationManager.NavigateTo(PageState.ReturnUrl, true);
|
NavigationManager.NavigateTo(PageState.ReturnUrl, true); // redirect to page being edited and reload
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
NavigationManager.NavigateTo(NavigateUrl(), true); // redirect to page being edited
|
NavigationManager.NavigateTo(NavigateUrl()); // redirect to page management
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -5,11 +5,11 @@
|
|||||||
@inject IStringLocalizer<Index> Localizer
|
@inject IStringLocalizer<Index> Localizer
|
||||||
@inject IStringLocalizer<SharedResources> SharedLocalizer
|
@inject IStringLocalizer<SharedResources> SharedLocalizer
|
||||||
|
|
||||||
@if (PageState.Pages != null && UserSecurity.IsAuthorized(PageState.User, RoleNames.Admin))
|
@if (_pages != null && UserSecurity.IsAuthorized(PageState.User, RoleNames.Admin))
|
||||||
{
|
{
|
||||||
<ActionLink Action="Add" Text="Add Page" ResourceKey="AddPage" />
|
<ActionLink Action="Add" Text="Add Page" ResourceKey="AddPage" />
|
||||||
|
|
||||||
<Pager Items="@PageState.Pages.Where(item => !item.IsDeleted)" SearchProperties="Name">
|
<Pager Items="@_pages.Where(item => !item.IsDeleted)" SearchProperties="Name">
|
||||||
<Header>
|
<Header>
|
||||||
<th style="width: 1px;"> </th>
|
<th style="width: 1px;"> </th>
|
||||||
<th style="width: 1px;"> </th>
|
<th style="width: 1px;"> </th>
|
||||||
@ -17,7 +17,7 @@
|
|||||||
<th>@SharedLocalizer["Name"]</th>
|
<th>@SharedLocalizer["Name"]</th>
|
||||||
</Header>
|
</Header>
|
||||||
<Row>
|
<Row>
|
||||||
<td><ActionLink Action="Edit" Parameters="@($"id=" + context.PageId.ToString())" ResourceKey="EditPage" /></td>
|
<td><ActionLink Action="Edit" Text="Edit" Parameters="@($"id=" + context.PageId.ToString())" ResourceKey="EditPage" /></td>
|
||||||
<td><ActionDialog Header="Delete Page" Message="@string.Format(Localizer["Confirm.Page.Delete"], context.Name)" Action="Delete" Security="SecurityAccessLevel.Admin" Class="btn btn-danger" OnClick="@(async () => await DeletePage(context))" ResourceKey="DeletePage" /></td>
|
<td><ActionDialog Header="Delete Page" Message="@string.Format(Localizer["Confirm.Page.Delete"], context.Name)" Action="Delete" Security="SecurityAccessLevel.Admin" Class="btn btn-danger" OnClick="@(async () => await DeletePage(context))" ResourceKey="DeletePage" /></td>
|
||||||
<td><button type="button" class="btn btn-secondary" @onclick="@(async () => NavigationManager.NavigateTo(Browse(context)))">@Localizer["Browse"]</button></td>
|
<td><button type="button" class="btn btn-secondary" @onclick="@(async () => NavigationManager.NavigateTo(Browse(context)))">@Localizer["Browse"]</button></td>
|
||||||
<td>@(new string('-', context.Level * 2))@(context.Name)</td>
|
<td>@(new string('-', context.Level * 2))@(context.Name)</td>
|
||||||
@ -28,6 +28,21 @@
|
|||||||
@code {
|
@code {
|
||||||
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Admin;
|
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Admin;
|
||||||
|
|
||||||
|
private List<Page> _pages;
|
||||||
|
|
||||||
|
protected override async Task OnInitializedAsync()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
_pages = await PageService.GetPagesAsync(PageState.Site.SiteId);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
await logger.LogError(ex, "Error Loading Pages {Error}", ex.Message);
|
||||||
|
AddModuleMessage(Localizer["Error.Page.Load"], MessageType.Error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private async Task DeletePage(Page page)
|
private async Task DeletePage(Page page)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
|
@ -22,7 +22,7 @@ else
|
|||||||
<th>@Localizer["Order"]</th>
|
<th>@Localizer["Order"]</th>
|
||||||
</Header>
|
</Header>
|
||||||
<Row>
|
<Row>
|
||||||
<td><ActionLink Action="Edit" Parameters="@($"id=" + context.ProfileId.ToString())" Security="SecurityAccessLevel.Edit" ResourceKey="EditProfile" /></td>
|
<td><ActionLink Action="Edit" Text="Edit" Parameters="@($"id=" + context.ProfileId.ToString())" Security="SecurityAccessLevel.Edit" ResourceKey="EditProfile" /></td>
|
||||||
<td><ActionDialog Header="Delete Profile" Message="@string.Format(Localizer["Confirm.Profile.Delete"], context.Name)" Action="Delete" Security="SecurityAccessLevel.Edit" Class="btn btn-danger" OnClick="@(async () => await DeleteProfile(context.ProfileId))" ResourceKey="DeleteProfile" /></td>
|
<td><ActionDialog Header="Delete Profile" Message="@string.Format(Localizer["Confirm.Profile.Delete"], context.Name)" Action="Delete" Security="SecurityAccessLevel.Edit" Class="btn btn-danger" OnClick="@(async () => await DeleteProfile(context.ProfileId))" ResourceKey="DeleteProfile" /></td>
|
||||||
<td>@context.Name</td>
|
<td>@context.Name</td>
|
||||||
<td>@context.Title</td>
|
<td>@context.Title</td>
|
||||||
|
@ -20,9 +20,9 @@ else
|
|||||||
<th>@SharedLocalizer["Name"]</th>
|
<th>@SharedLocalizer["Name"]</th>
|
||||||
</Header>
|
</Header>
|
||||||
<Row>
|
<Row>
|
||||||
<td><ActionLink Action="Edit" Parameters="@($"id=" + context.RoleId.ToString())" Security="SecurityAccessLevel.Edit" Disabled="@(context.IsSystem)" ResourceKey="Edit" /></td>
|
<td><ActionLink Action="Edit" Text="Edit" Parameters="@($"id=" + context.RoleId.ToString())" Security="SecurityAccessLevel.Edit" Disabled="@(context.IsSystem)" ResourceKey="Edit" /></td>
|
||||||
<td><ActionDialog Header="Delete Role" Message="@string.Format(Localizer["Confirm.DeleteUser"], context.Name)" Action="Delete" Security="SecurityAccessLevel.Edit" Class="btn btn-danger" OnClick="@(async () => await DeleteRole(context))" Disabled="@(context.IsSystem)" ResourceKey="DeleteRole" /></td>
|
<td><ActionDialog Header="Delete Role" Message="@string.Format(Localizer["Confirm.DeleteUser"], context.Name)" Action="Delete" Security="SecurityAccessLevel.Edit" Class="btn btn-danger" OnClick="@(async () => await DeleteRole(context))" Disabled="@(context.IsSystem)" ResourceKey="DeleteRole" /></td>
|
||||||
<td><ActionLink Action="Users" Parameters="@($"id=" + context.RoleId.ToString())" Security="SecurityAccessLevel.Edit" ResourceKey="Users" /></td>
|
<td><ActionLink Action="Users" Text="Users" Parameters="@($"id=" + context.RoleId.ToString())" Security="SecurityAccessLevel.Edit" ResourceKey="Users" /></td>
|
||||||
<td>@context.Name</td>
|
<td>@context.Name</td>
|
||||||
</Row>
|
</Row>
|
||||||
</Pager>
|
</Pager>
|
||||||
|
121
Oqtane.Client/Modules/Admin/Search/Index.razor
Normal file
121
Oqtane.Client/Modules/Admin/Search/Index.razor
Normal file
@ -0,0 +1,121 @@
|
|||||||
|
@namespace Oqtane.Modules.Admin.Search
|
||||||
|
@inherits ModuleBase
|
||||||
|
@inject ISettingService SettingService
|
||||||
|
@inject IStringLocalizer<Index> Localizer
|
||||||
|
@inject IStringLocalizer<SharedResources> SharedLocalizer
|
||||||
|
|
||||||
|
<div class="container">
|
||||||
|
<div class="row mb-1 align-items-center">
|
||||||
|
<Label Class="col-sm-3" For="searchprovider" HelpText="Specify the search provider for this site" ResourceKey="SearchProvider">Search Provider: </Label>
|
||||||
|
<div class="col-sm-9">
|
||||||
|
<input id="searchprovider" class="form-control" @bind="@_searchProvider" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row mb-1 align-items-center">
|
||||||
|
<Label Class="col-sm-3" For="enabled" HelpText="Specify if search indexing is enabled" ResourceKey="Enabled">Indexing Enabled? </Label>
|
||||||
|
<div class="col-sm-9">
|
||||||
|
<select id="enabled" class="form-select" @bind="@_enabled">
|
||||||
|
<option value="True">@SharedLocalizer["Yes"]</option>
|
||||||
|
<option value="False">@SharedLocalizer["No"]</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row mb-1 align-items-center">
|
||||||
|
<Label Class="col-sm-3" For="lastindexedon" HelpText="The date/time which the site was last indexed on" ResourceKey="LastIndexedOn">Last Indexed: </Label>
|
||||||
|
<div class="col-sm-9">
|
||||||
|
<input id="lastindexedon" class="form-control" @bind="@_lastIndexedOn" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row mb-1 align-items-center">
|
||||||
|
<Label Class="col-sm-3" For="ignorepages" HelpText="Comma delimited list of pages which should be ignored (based on their path)" ResourceKey="IgnorePages">Ignore Pages: </Label>
|
||||||
|
<div class="col-sm-9">
|
||||||
|
<textarea id="ignorepages" class="form-control" @bind="@_ignorePages" rows="3"></textarea>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row mb-1 align-items-center">
|
||||||
|
<Label Class="col-sm-3" For="ignoreentities" HelpText="Comma delimited list of entities which should be ignored" ResourceKey="IgnoreEntities">Ignore Entities: </Label>
|
||||||
|
<div class="col-sm-9">
|
||||||
|
<textarea id="ignoreentities" class="form-control" @bind="@_ignoreEntities" rows="3"></textarea>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row mb-1 align-items-center">
|
||||||
|
<Label Class="col-sm-3" For="minimumwordlength" HelpText="Minimum length of a word to be indexed" ResourceKey="MinimumWordLength">Word Length: </Label>
|
||||||
|
<div class="col-sm-9">
|
||||||
|
<input id="minimumwordlength" class="form-control" type="number" min="0" step="1" @bind="@_minimumWordLength" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row mb-1 align-items-center">
|
||||||
|
<Label Class="col-sm-3" For="ignorewords" HelpText="Comma delimited list of words which should be ignored" ResourceKey="IgnoreWords">Ignore Words: </Label>
|
||||||
|
<div class="col-sm-9">
|
||||||
|
<textarea id="ignorewords" class="form-control" @bind="@_ignoreWords" rows="3"></textarea>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<br /><br />
|
||||||
|
<button type="button" class="btn btn-success" @onclick="Save">@SharedLocalizer["Save"]</button>
|
||||||
|
<ActionDialog Header="Reindex" Message="Are You Sure You Wish To Reindex Search Content?" Action="Reindex" Class="btn btn-danger" OnClick="@(async () => await Reindex())" ResourceKey="Reindex" />
|
||||||
|
<br /><br />
|
||||||
|
|
||||||
|
@code {
|
||||||
|
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Admin;
|
||||||
|
|
||||||
|
private string _searchProvider;
|
||||||
|
private string _enabled = "True";
|
||||||
|
private string _lastIndexedOn = "";
|
||||||
|
private string _ignorePages = "";
|
||||||
|
private string _ignoreEntities = "";
|
||||||
|
private string _minimumWordLength = "3";
|
||||||
|
private string _ignoreWords = "the,be,to,of,and,a,i,in,that,have,it,for,not,on,with,he,as,you,do,at,this,but,his,by,from,they,we,say,her,she,or,an,will,my,one,all,would,there,their,what,so,up,out,if,about,who,get,which,go,me,when,make,can,like,time,no,just,him,know,take,people,into,year,your,good,some,could,them,see,other,than,then,now,look,only,come,its,over,think,also,back,after,use,two,how,our,work,first,well,way,even,new,want,because,any,these,give,day,most,us";
|
||||||
|
|
||||||
|
protected override async Task OnInitializedAsync()
|
||||||
|
{
|
||||||
|
var settings = await SettingService.GetSiteSettingsAsync(PageState.Site.SiteId);
|
||||||
|
_searchProvider = SettingService.GetSetting(settings, "Search_SearchProvider", Constants.DefaultSearchProviderName);
|
||||||
|
_enabled = SettingService.GetSetting(settings, "Search_Enabled", _enabled);
|
||||||
|
_lastIndexedOn = SettingService.GetSetting(settings, "Search_LastIndexedOn", _lastIndexedOn);
|
||||||
|
_ignorePages = SettingService.GetSetting(settings, "Search_IgnorePages", _ignorePages);
|
||||||
|
_ignoreEntities = SettingService.GetSetting(settings, "Search_IgnoreEntities", _ignoreEntities);
|
||||||
|
_minimumWordLength = SettingService.GetSetting(settings, "Search_MininumWordLength", _minimumWordLength);
|
||||||
|
_ignoreWords = SettingService.GetSetting(settings, "Search_IgnoreWords", _ignoreWords);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task Save()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var settings = await SettingService.GetSiteSettingsAsync(PageState.Site.SiteId);
|
||||||
|
settings = SettingService.SetSetting(settings, "Search_SearchProvider", _searchProvider);
|
||||||
|
settings = SettingService.SetSetting(settings, "Search_Enabled", _enabled, true);
|
||||||
|
settings = SettingService.SetSetting(settings, "Search_LastIndexedOn", _lastIndexedOn, true);
|
||||||
|
settings = SettingService.SetSetting(settings, "Search_IgnorePages", _ignorePages, true);
|
||||||
|
settings = SettingService.SetSetting(settings, "Search_IgnoreEntities", _ignoreEntities, true);
|
||||||
|
settings = SettingService.SetSetting(settings, "Search_MininumWordLength", _minimumWordLength, true);
|
||||||
|
settings = SettingService.SetSetting(settings, "Search_IgnoreWords", _ignoreWords, true);
|
||||||
|
await SettingService.UpdateSiteSettingsAsync(settings, PageState.Site.SiteId);
|
||||||
|
AddModuleMessage(Localizer["Success.Save"], MessageType.Success);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
await logger.LogError(ex, "Error Saving Search Settings {Error}", ex.Message);
|
||||||
|
AddModuleMessage(Localizer["Error.Save"], MessageType.Error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task Reindex()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
_lastIndexedOn = DateTime.MinValue.ToString();
|
||||||
|
var settings = await SettingService.GetSiteSettingsAsync(PageState.Site.SiteId);
|
||||||
|
settings = SettingService.SetSetting(settings, "Search_LastIndexedOn", _lastIndexedOn, true);
|
||||||
|
await SettingService.UpdateSiteSettingsAsync(settings, PageState.Site.SiteId);
|
||||||
|
AddModuleMessage(Localizer["Message.Reindex"], MessageType.Success);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
await logger.LogError(ex, "Error Saving Search Settings {Error}", ex.Message);
|
||||||
|
AddModuleMessage(Localizer["Error.Save"], MessageType.Error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
141
Oqtane.Client/Modules/Admin/SearchResults/Index.razor
Normal file
141
Oqtane.Client/Modules/Admin/SearchResults/Index.razor
Normal file
@ -0,0 +1,141 @@
|
|||||||
|
@using Oqtane.Services
|
||||||
|
@using System.Net
|
||||||
|
@namespace Oqtane.Modules.Admin.SearchResults
|
||||||
|
@inherits ModuleBase
|
||||||
|
@inject NavigationManager NavigationManager
|
||||||
|
@inject ISearchResultsService SearchResultsService
|
||||||
|
@inject ISettingService SettingService
|
||||||
|
@inject IStringLocalizer<Index> Localizer
|
||||||
|
@inject IStringLocalizer<SharedResources> SharedLocalizer
|
||||||
|
|
||||||
|
<div class="search-result-container">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col">
|
||||||
|
<form method="post" @formname="SearchResultsForm" @onsubmit="Search" data-enhance>
|
||||||
|
<div class="input-group mb-3">
|
||||||
|
<span class="input-group-text">@Localizer["SearchLabel"]</span>
|
||||||
|
<input type="hidden" name="@Constants.RequestVerificationToken" value="@SiteState.AntiForgeryToken" />
|
||||||
|
<input type="text" name="keywords" class="form-control shadow-none" maxlength="50"
|
||||||
|
aria-label="Keywords"
|
||||||
|
placeholder="@Localizer["SearchPlaceholder"]"
|
||||||
|
@bind="@_keywords">
|
||||||
|
<button class="btn btn-primary" type="submit">@SharedLocalizer["Search"]</button>
|
||||||
|
<a class="btn btn-secondary" href="@NavigateUrl()">@SharedLocalizer["Reset"]</a>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-12 mb-3">
|
||||||
|
@if (_loading)
|
||||||
|
{
|
||||||
|
<div class="app-progress-indicator"></div>
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
@if (_searchResults != null && _searchResults.Results != null)
|
||||||
|
{
|
||||||
|
if (_searchResults.Results.Any())
|
||||||
|
{
|
||||||
|
<Pager Items="@_searchResults?.Results"
|
||||||
|
Format="Grid"
|
||||||
|
Columns="1"
|
||||||
|
Toolbar="Bottom"
|
||||||
|
Parameters="@($"q={_keywords}")">
|
||||||
|
<Row>
|
||||||
|
<div class="search-item mb-2">
|
||||||
|
<h4 class="mb-1"><a href="@context.Url">@context.Title</a></h4>
|
||||||
|
<p class="mb-0 text-muted">@((MarkupString)context.Snippet)</p>
|
||||||
|
</div>
|
||||||
|
</Row>
|
||||||
|
</Pager>
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
<div class="alert alert-info show mt-3" role="alert">
|
||||||
|
@Localizer["NoResult"]
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
<div class="clearfix"></div>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
@code {
|
||||||
|
public override string RenderMode => RenderModes.Static;
|
||||||
|
|
||||||
|
private string _includeEntities;
|
||||||
|
private string _excludeEntities;
|
||||||
|
private string _fromDate;
|
||||||
|
private string _toDate;
|
||||||
|
private string _pageSize;
|
||||||
|
private string _sortField;
|
||||||
|
private string _sortOrder;
|
||||||
|
private string _bodyLength;
|
||||||
|
|
||||||
|
private string _keywords;
|
||||||
|
private SearchResults _searchResults;
|
||||||
|
private bool _loading;
|
||||||
|
|
||||||
|
[SupplyParameterFromForm(FormName = "SearchResultsForm")]
|
||||||
|
public string KeyWords { get => ""; set => _keywords = value; }
|
||||||
|
|
||||||
|
protected override async Task OnInitializedAsync()
|
||||||
|
{
|
||||||
|
_includeEntities = SettingService.GetSetting(ModuleState.Settings, "SearchResults_IncludeEntities", "");
|
||||||
|
_excludeEntities = SettingService.GetSetting(ModuleState.Settings, "SearchResults_ExcludeEntities", "");
|
||||||
|
_fromDate = SettingService.GetSetting(ModuleState.Settings, "SearchResults_FromDate", DateTime.MinValue.ToString());
|
||||||
|
_toDate = SettingService.GetSetting(ModuleState.Settings, "SearchResults_ToDate", DateTime.MaxValue.ToString());
|
||||||
|
_pageSize = SettingService.GetSetting(ModuleState.Settings, "SearchResults_PageSize", int.MaxValue.ToString());
|
||||||
|
_sortField = SettingService.GetSetting(ModuleState.Settings, "SearchResults_SortField", "Relevance");
|
||||||
|
_sortOrder = SettingService.GetSetting(ModuleState.Settings, "SearchResults_SortOrder", "Descending");
|
||||||
|
_bodyLength = SettingService.GetSetting(ModuleState.Settings, "SearchResults_BodyLength", "255");
|
||||||
|
|
||||||
|
if (_keywords == null && PageState.QueryString.ContainsKey("q"))
|
||||||
|
{
|
||||||
|
_keywords = WebUtility.UrlDecode(PageState.QueryString["q"]);
|
||||||
|
await PerformSearch();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Search()
|
||||||
|
{
|
||||||
|
NavigationManager.NavigateTo(NavigateUrl(PageState.Page.Path, $"page=1&q={WebUtility.UrlEncode(_keywords)}"));
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task PerformSearch()
|
||||||
|
{
|
||||||
|
_loading = true;
|
||||||
|
StateHasChanged();
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(_keywords))
|
||||||
|
{
|
||||||
|
var searchQuery = new SearchQuery
|
||||||
|
{
|
||||||
|
SiteId = PageState.Site.SiteId,
|
||||||
|
Alias = PageState.Alias,
|
||||||
|
Keywords = _keywords,
|
||||||
|
IncludeEntities = _includeEntities,
|
||||||
|
ExcludeEntities = _excludeEntities,
|
||||||
|
FromDate = (!string.IsNullOrEmpty(_fromDate)) ? DateTime.Parse(_fromDate) : DateTime.MinValue,
|
||||||
|
ToDate = (!string.IsNullOrEmpty(_toDate)) ? DateTime.Parse(_toDate) : DateTime.MaxValue,
|
||||||
|
PageSize = (!string.IsNullOrEmpty(_pageSize)) ? int.Parse(_pageSize) : int.MaxValue,
|
||||||
|
PageIndex = 0,
|
||||||
|
SortField = (!string.IsNullOrEmpty(_sortField)) ? (SearchSortField)Enum.Parse(typeof(SearchSortField), _sortField) : SearchSortField.Relevance,
|
||||||
|
SortOrder = (!string.IsNullOrEmpty(_sortOrder)) ? (SearchSortOrder)Enum.Parse(typeof(SearchSortOrder), _sortOrder) : SearchSortOrder.Descending,
|
||||||
|
BodyLength = (!string.IsNullOrEmpty(_bodyLength)) ? int.Parse(_bodyLength) : 255
|
||||||
|
};
|
||||||
|
|
||||||
|
_searchResults = await SearchResultsService.GetSearchResultsAsync(searchQuery);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
AddModuleMessage(Localizer["NoCriteria"], MessageType.Info, "bottom");
|
||||||
|
}
|
||||||
|
|
||||||
|
_loading = false;
|
||||||
|
StateHasChanged();
|
||||||
|
}
|
||||||
|
}
|
19
Oqtane.Client/Modules/Admin/SearchResults/ModuleInfo.cs
Normal file
19
Oqtane.Client/Modules/Admin/SearchResults/ModuleInfo.cs
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
using Oqtane.Documentation;
|
||||||
|
using Oqtane.Models;
|
||||||
|
using Oqtane.Shared;
|
||||||
|
|
||||||
|
namespace Oqtane.Modules.Admin.SearchResults
|
||||||
|
{
|
||||||
|
[PrivateApi("Mark this as private, since it's not very useful in the public docs")]
|
||||||
|
public class ModuleInfo : IModule
|
||||||
|
{
|
||||||
|
public ModuleDefinition ModuleDefinition => new ModuleDefinition
|
||||||
|
{
|
||||||
|
Name = "Search Results",
|
||||||
|
Description = "Search Results",
|
||||||
|
Categories = "Admin",
|
||||||
|
Version = Constants.Version,
|
||||||
|
SettingsType = "Oqtane.Modules.Admin.SearchResults.Settings, Oqtane.Client"
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
123
Oqtane.Client/Modules/Admin/SearchResults/Settings.razor
Normal file
123
Oqtane.Client/Modules/Admin/SearchResults/Settings.razor
Normal file
@ -0,0 +1,123 @@
|
|||||||
|
@namespace Oqtane.Modules.Admin.SearchResults
|
||||||
|
@inherits ModuleBase
|
||||||
|
@inject ISettingService SettingService
|
||||||
|
@implements Oqtane.Interfaces.ISettingsControl
|
||||||
|
@inject IStringLocalizer<Settings> Localizer
|
||||||
|
@inject IStringLocalizer<SharedResources> SharedLocalizer
|
||||||
|
|
||||||
|
<form @ref="form" class="@(validated ? "was-validated" : "needs-validation")" novalidate>
|
||||||
|
<div class="container">
|
||||||
|
<div class="row mb-1 align-items-center">
|
||||||
|
<Label Class="col-sm-3" For="includeentities" ResourceKey="IncludeEntities" ResourceType="@resourceType" HelpText="Comma delimited list of entities to include in the search results. By default all entities will be included.">Include Entities: </Label>
|
||||||
|
<div class="col-sm-9">
|
||||||
|
<input id="includeentities" type="text" class="form-control" @bind="@_includeEntities" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row mb-1 align-items-center">
|
||||||
|
<Label Class="col-sm-3" For="excludeentities" ResourceKey="ExcludeEntities" ResourceType="@resourceType" HelpText="Comma delimited list of entities to exclude from search results. By default no entities will be excluded.">Exclude Entities: </Label>
|
||||||
|
<div class="col-sm-9">
|
||||||
|
<input id="excludeentities" class="form-control" @bind="@_excludeEntities" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row mb-1 align-items-center">
|
||||||
|
<Label Class="col-sm-3" For="daterange" ResourceKey="DateRange" ResourceType="@resourceType" HelpText="Enter the date range for search results. The default includes all content.">Date Range: </Label>
|
||||||
|
<div class="col-sm-9">
|
||||||
|
<div class="input-group">
|
||||||
|
<input type="date" class="form-control" @bind="@_fromDate" />
|
||||||
|
<span class="input-group-text">@Localizer["To"]</span>
|
||||||
|
<input type="date" class="form-control" @bind="@_toDate" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row mb-1 align-items-center">
|
||||||
|
<Label Class="col-sm-3" For="pagesize" ResourceKey="PageSize" ResourceType="@resourceType" HelpText="The maximum number of search results to retrieve. The default is unlimited.">Page Size: </Label>
|
||||||
|
<div class="col-sm-9">
|
||||||
|
<input id="pagesize" type="text" class="form-control" @bind="@_pageSize" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<hr />
|
||||||
|
<div class="row mb-1 align-items-center">
|
||||||
|
<Label Class="col-sm-3" For="sortfield" ResourceKey="SortField" ResourceType="@resourceType" HelpText="Specify the default sort field">Sort By: </Label>
|
||||||
|
<div class="col-sm-9">
|
||||||
|
<select id="softfield" class="form-select" @bind="@_sortField">
|
||||||
|
<option value="Relevance">@Localizer["Relevance"]</option>
|
||||||
|
<option value="Title">@Localizer["Title"]</option>
|
||||||
|
<option value="LastModified">@Localizer["LastModified"]</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row mb-1 align-items-center">
|
||||||
|
<Label Class="col-sm-3" For="sortorder" ResourceKey="SortOrder" ResourceType="@resourceType" HelpText="Specify the default sort order">Sort Order: </Label>
|
||||||
|
<div class="col-sm-9">
|
||||||
|
<select id="softorder" class="form-select" @bind="@_sortOrder">
|
||||||
|
<option value="Ascending">@Localizer["Ascending"]</option>
|
||||||
|
<option value="Descending">@Localizer["Descending"]</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row mb-1 align-items-center">
|
||||||
|
<Label Class="col-sm-3" For="bodylength" ResourceKey="BodyLength" ResourceType="@resourceType" HelpText="The number of characters displayed for each search result summary. The default is 255 characters.">Body Size: </Label>
|
||||||
|
<div class="col-sm-9">
|
||||||
|
<input id="bodylength" type="text" class="form-control" @bind="@_bodyLength" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
@code {
|
||||||
|
private string resourceType = "Oqtane.Modules.Admin.SearchResults.Settings, Oqtane.Client"; // for localization
|
||||||
|
|
||||||
|
private ElementReference form;
|
||||||
|
private bool validated = false;
|
||||||
|
|
||||||
|
private string _includeEntities;
|
||||||
|
private string _excludeEntities;
|
||||||
|
private DateTime? _fromDate = null;
|
||||||
|
private DateTime? _toDate = null;
|
||||||
|
private string _pageSize;
|
||||||
|
private string _sortField;
|
||||||
|
private string _sortOrder;
|
||||||
|
private string _bodyLength;
|
||||||
|
|
||||||
|
protected override void OnInitialized()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
_includeEntities = SettingService.GetSetting(ModuleState.Settings, "SearchResults_IncludeEntities", "");
|
||||||
|
_excludeEntities = SettingService.GetSetting(ModuleState.Settings, "SearchResults_ExcludeEntities", "");
|
||||||
|
var fromDate = SettingService.GetSetting(ModuleState.Settings, "SearchResults_FromDate", "");
|
||||||
|
_fromDate = (string.IsNullOrEmpty(fromDate)) ? null : DateTime.Parse(fromDate);
|
||||||
|
var toDate = SettingService.GetSetting(ModuleState.Settings, "SearchResults_ToDate", "");
|
||||||
|
_toDate = (string.IsNullOrEmpty(toDate)) ? null : DateTime.Parse(toDate);
|
||||||
|
_pageSize = SettingService.GetSetting(ModuleState.Settings, "SearchResults_PageSize", "");
|
||||||
|
_sortField = SettingService.GetSetting(ModuleState.Settings, "SearchResults_SortField", "Relevance");
|
||||||
|
_sortOrder = SettingService.GetSetting(ModuleState.Settings, "SearchResults_SortOrder", "Descending");
|
||||||
|
_bodyLength = SettingService.GetSetting(ModuleState.Settings, "SearchResults_BodyLength", "255");
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
AddModuleMessage(ex.Message, MessageType.Error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task UpdateSettings()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var settings = await SettingService.GetModuleSettingsAsync(ModuleState.ModuleId);
|
||||||
|
settings = SettingService.SetSetting(settings, "SearchResults_IncludeEntities", _includeEntities);
|
||||||
|
settings = SettingService.SetSetting(settings, "SearchResults_ExcludeEntities", _excludeEntities);
|
||||||
|
settings = SettingService.SetSetting(settings, "SearchResults_From", _fromDate.ToString());
|
||||||
|
settings = SettingService.SetSetting(settings, "SearchResults_To", _toDate.ToString());
|
||||||
|
settings = SettingService.SetSetting(settings, "SearchResults_PageSize", _pageSize);
|
||||||
|
settings = SettingService.SetSetting(settings, "SearchResults_SortField", _sortField);
|
||||||
|
settings = SettingService.SetSetting(settings, "SearchResults_SortOrder", _sortOrder);
|
||||||
|
settings = SettingService.SetSetting(settings, "SearchResults_BodyLength", _bodyLength);
|
||||||
|
await SettingService.UpdateModuleSettingsAsync(settings, ModuleState.ModuleId);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
AddModuleMessage(ex.Message, MessageType.Error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,13 +1,16 @@
|
|||||||
@namespace Oqtane.Modules.Admin.Site
|
@namespace Oqtane.Modules.Admin.Site
|
||||||
@inherits ModuleBase
|
@inherits ModuleBase
|
||||||
@using System.Text.RegularExpressions
|
@using System.Text.RegularExpressions
|
||||||
|
@using Microsoft.Extensions.DependencyInjection
|
||||||
@inject NavigationManager NavigationManager
|
@inject NavigationManager NavigationManager
|
||||||
@inject ISiteService SiteService
|
@inject ISiteService SiteService
|
||||||
|
@inject IPageService PageService
|
||||||
@inject ITenantService TenantService
|
@inject ITenantService TenantService
|
||||||
@inject IDatabaseService DatabaseService
|
@inject IDatabaseService DatabaseService
|
||||||
@inject IAliasService AliasService
|
@inject IAliasService AliasService
|
||||||
@inject IThemeService ThemeService
|
@inject IThemeService ThemeService
|
||||||
@inject ISettingService SettingService
|
@inject ISettingService SettingService
|
||||||
|
@inject IServiceProvider ServiceProvider
|
||||||
@inject IStringLocalizer<Index> Localizer
|
@inject IStringLocalizer<Index> Localizer
|
||||||
@inject INotificationService NotificationService
|
@inject INotificationService NotificationService
|
||||||
@inject IStringLocalizer<SharedResources> SharedLocalizer
|
@inject IStringLocalizer<SharedResources> SharedLocalizer
|
||||||
@ -27,7 +30,7 @@
|
|||||||
<div class="col-sm-9">
|
<div class="col-sm-9">
|
||||||
<select id="homepage" class="form-select" @bind="@_homepageid" required>
|
<select id="homepage" class="form-select" @bind="@_homepageid" required>
|
||||||
<option value="-"><@SharedLocalizer["Not Specified"]></option>
|
<option value="-"><@SharedLocalizer["Not Specified"]></option>
|
||||||
@foreach (Page page in PageState.Pages)
|
@foreach (Page page in _pages)
|
||||||
{
|
{
|
||||||
if (UserSecurity.ContainsRole(page.PermissionList, PermissionNames.View, RoleNames.Everyone))
|
if (UserSecurity.ContainsRole(page.PermissionList, PermissionNames.View, RoleNames.Everyone))
|
||||||
{
|
{
|
||||||
@ -74,7 +77,7 @@
|
|||||||
<div class="row mb-1 align-items-center">
|
<div class="row mb-1 align-items-center">
|
||||||
<Label Class="col-sm-3" For="logo" HelpText="Specify a logo for the site" ResourceKey="Logo">Logo: </Label>
|
<Label Class="col-sm-3" For="logo" HelpText="Specify a logo for the site" ResourceKey="Logo">Logo: </Label>
|
||||||
<div class="col-sm-9">
|
<div class="col-sm-9">
|
||||||
<FileManager FileId="@_logofileid" Filter="@_ImageFiles" @ref="_logofilemanager" />
|
<FileManager FileId="@_logofileid" Filter="@_imageFiles" @ref="_logofilemanager" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row mb-1 align-items-center">
|
<div class="row mb-1 align-items-center">
|
||||||
@ -125,18 +128,32 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</Section>
|
</Section>
|
||||||
<Section Name="FileExtensions" Heading="File Extensions" ResourceKey="FileExtensions">
|
<Section Name="Functionality" Heading="Functionality" ResourceKey="Functionality">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
|
<div class="row mb-1 align-items-center">
|
||||||
|
<Label Class="col-sm-3" For="textEditor" HelpText="Select the text editor for the site" ResourceKey="TextEditor">Text Editor: </Label>
|
||||||
|
<div class="col-sm-9">
|
||||||
|
<select id="textEditor" class="form-select" @bind="@_textEditor" required>
|
||||||
|
@if (_textEditors != null)
|
||||||
|
{
|
||||||
|
@foreach (var textEditor in _textEditors)
|
||||||
|
{
|
||||||
|
<option value="@textEditor.Value">@textEditor.Key</option>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div class="row mb-1 align-items-center">
|
<div class="row mb-1 align-items-center">
|
||||||
<Label Class="col-sm-3" For="imageExt" HelpText="Enter a comma separated list of image file extensions" ResourceKey="ImageExtensions">Image Extensions: </Label>
|
<Label Class="col-sm-3" For="imageExt" HelpText="Enter a comma separated list of image file extensions" ResourceKey="ImageExtensions">Image Extensions: </Label>
|
||||||
<div class="col-sm-9">
|
<div class="col-sm-9">
|
||||||
<input id="imageExt" spellcheck="false" class="form-control" @bind="@_ImageFiles" />
|
<input id="imageExt" spellcheck="false" class="form-control" @bind="@_imageFiles" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row mb-1 align-items-center">
|
<div class="row mb-1 align-items-center">
|
||||||
<Label Class="col-sm-3" For="uploadableFileExt" HelpText="Enter a comma separated list of uploadable file extensions" ResourceKey="UploadableFileExtensions">Uploadable File Extensions: </Label>
|
<Label Class="col-sm-3" For="uploadableFileExt" HelpText="Enter a comma separated list of uploadable file extensions" ResourceKey="UploadableFileExtensions">Uploadable File Extensions: </Label>
|
||||||
<div class="col-sm-9">
|
<div class="col-sm-9">
|
||||||
<input id="uploadableFileExt" spellcheck="false" class="form-control" @bind="@_UploadableFiles" />
|
<input id="uploadableFileExt" spellcheck="false" class="form-control" @bind="@_uploadableFiles" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -292,7 +309,7 @@
|
|||||||
}
|
}
|
||||||
</td>
|
</td>
|
||||||
<td>@context.Name</td>
|
<td>@context.Name</td>
|
||||||
<td>@context.IsDefault</td>
|
<td>@((context.IsDefault) ? SharedLocalizer["Yes"] : SharedLocalizer["No"])</td>
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -319,7 +336,7 @@
|
|||||||
<div class="row mb-1 align-items-center">
|
<div class="row mb-1 align-items-center">
|
||||||
<Label Class="col-sm-3" For="rendermode" HelpText="The default render mode for the site" ResourceKey="Rendermode">Render Mode: </Label>
|
<Label Class="col-sm-3" For="rendermode" HelpText="The default render mode for the site" ResourceKey="Rendermode">Render Mode: </Label>
|
||||||
<div class="col-sm-9">
|
<div class="col-sm-9">
|
||||||
<select id="rendermode" class="form-select" @bind="@_rendermode" required>
|
<select id="rendermode" class="form-select" value="@_rendermode" @onchange="(e => RenderModeChanged(e))" required>
|
||||||
<option value="@RenderModes.Interactive">@(SharedLocalizer["RenderMode" + @RenderModes.Interactive])</option>
|
<option value="@RenderModes.Interactive">@(SharedLocalizer["RenderMode" + @RenderModes.Interactive])</option>
|
||||||
<option value="@RenderModes.Static">@(SharedLocalizer["RenderMode" + @RenderModes.Static])</option>
|
<option value="@RenderModes.Static">@(SharedLocalizer["RenderMode" + @RenderModes.Static])</option>
|
||||||
<option value="@RenderModes.Headless">@(SharedLocalizer["RenderMode" + @RenderModes.Headless])</option>
|
<option value="@RenderModes.Headless">@(SharedLocalizer["RenderMode" + @RenderModes.Headless])</option>
|
||||||
@ -337,7 +354,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row mb-1 align-items-center">
|
<div class="row mb-1 align-items-center">
|
||||||
<Label Class="col-sm-3" For="prerender" HelpText="Specifies if interactive components should prerender their output" ResourceKey="Prerender">Prerender? </Label>
|
<Label Class="col-sm-3" For="prerender" HelpText="Specifies if interactive components should prerender their output on the server" ResourceKey="Prerender">Prerender: </Label>
|
||||||
<div class="col-sm-9">
|
<div class="col-sm-9">
|
||||||
<select id="prerender" class="form-select" @bind="@_prerender" required>
|
<select id="prerender" class="form-select" @bind="@_prerender" required>
|
||||||
<option value="True">@SharedLocalizer["Yes"]</option>
|
<option value="True">@SharedLocalizer["Yes"]</option>
|
||||||
@ -394,12 +411,15 @@
|
|||||||
private bool _initialized = false;
|
private bool _initialized = false;
|
||||||
private List<ThemeControl> _themes = new List<ThemeControl>();
|
private List<ThemeControl> _themes = new List<ThemeControl>();
|
||||||
private List<ThemeControl> _containers = new List<ThemeControl>();
|
private List<ThemeControl> _containers = new List<ThemeControl>();
|
||||||
|
private List<Page> _pages;
|
||||||
|
|
||||||
private string _name = string.Empty;
|
private string _name = string.Empty;
|
||||||
private string _homepageid = "-";
|
private string _homepageid = "-";
|
||||||
private string _isdeleted;
|
private string _isdeleted;
|
||||||
private string _sitemap = "";
|
private string _sitemap = "";
|
||||||
private string _siteguid = "";
|
private string _siteguid = "";
|
||||||
private string _version = "";
|
private string _version = "";
|
||||||
|
|
||||||
private int _logofileid = -1;
|
private int _logofileid = -1;
|
||||||
private FileManager _logofilemanager;
|
private FileManager _logofilemanager;
|
||||||
private int _faviconfileid = -1;
|
private int _faviconfileid = -1;
|
||||||
@ -407,8 +427,15 @@
|
|||||||
private string _themetype = "";
|
private string _themetype = "";
|
||||||
private string _containertype = "";
|
private string _containertype = "";
|
||||||
private string _admincontainertype = "";
|
private string _admincontainertype = "";
|
||||||
|
|
||||||
|
private Dictionary<string, string> _textEditors = new Dictionary<string, string>();
|
||||||
|
private string _textEditor = "";
|
||||||
|
private string _imageFiles = string.Empty;
|
||||||
|
private string _uploadableFiles = string.Empty;
|
||||||
|
|
||||||
private string _headcontent = string.Empty;
|
private string _headcontent = string.Empty;
|
||||||
private string _bodycontent = string.Empty;
|
private string _bodycontent = string.Empty;
|
||||||
|
|
||||||
private string _smtphost = string.Empty;
|
private string _smtphost = string.Empty;
|
||||||
private string _smtpport = string.Empty;
|
private string _smtpport = string.Empty;
|
||||||
private string _smtpssl = "False";
|
private string _smtpssl = "False";
|
||||||
@ -419,25 +446,28 @@
|
|||||||
private string _smtpsender = string.Empty;
|
private string _smtpsender = string.Empty;
|
||||||
private string _smtprelay = "False";
|
private string _smtprelay = "False";
|
||||||
private string _smtpenabled = "True";
|
private string _smtpenabled = "True";
|
||||||
private string _ImageFiles = string.Empty;
|
|
||||||
private string _UploadableFiles = string.Empty;
|
|
||||||
private int _retention = 30;
|
private int _retention = 30;
|
||||||
|
|
||||||
private string _pwaisenabled;
|
private string _pwaisenabled;
|
||||||
private int _pwaappiconfileid = -1;
|
private int _pwaappiconfileid = -1;
|
||||||
private FileManager _pwaappiconfilemanager;
|
private FileManager _pwaappiconfilemanager;
|
||||||
private int _pwasplashiconfileid = -1;
|
private int _pwasplashiconfileid = -1;
|
||||||
private FileManager _pwasplashiconfilemanager;
|
private FileManager _pwasplashiconfilemanager;
|
||||||
|
|
||||||
private List<Alias> _aliases;
|
private List<Alias> _aliases;
|
||||||
private int _aliasid = -1;
|
private int _aliasid = -1;
|
||||||
private string _aliasname;
|
private string _aliasname;
|
||||||
private string _defaultalias;
|
private string _defaultalias;
|
||||||
|
|
||||||
private string _rendermode = RenderModes.Interactive;
|
private string _rendermode = RenderModes.Interactive;
|
||||||
private string _runtime = Runtimes.Server;
|
private string _runtime = Runtimes.Server;
|
||||||
private string _prerender = "True";
|
private string _prerender = "True";
|
||||||
private string _hybrid = "False";
|
private string _hybrid = "False";
|
||||||
|
|
||||||
private string _tenant = string.Empty;
|
private string _tenant = string.Empty;
|
||||||
private string _database = string.Empty;
|
private string _database = string.Empty;
|
||||||
private string _connectionstring = string.Empty;
|
private string _connectionstring = string.Empty;
|
||||||
|
|
||||||
private string _createdby;
|
private string _createdby;
|
||||||
private DateTime _createdon;
|
private DateTime _createdon;
|
||||||
private string _modifiedby;
|
private string _modifiedby;
|
||||||
@ -454,6 +484,10 @@
|
|||||||
Site site = await SiteService.GetSiteAsync(PageState.Site.SiteId);
|
Site site = await SiteService.GetSiteAsync(PageState.Site.SiteId);
|
||||||
if (site != null)
|
if (site != null)
|
||||||
{
|
{
|
||||||
|
var settings = await SettingService.GetSiteSettingsAsync(site.SiteId);
|
||||||
|
|
||||||
|
_pages = await PageService.GetPagesAsync(PageState.Site.SiteId);
|
||||||
|
|
||||||
_name = site.Name;
|
_name = site.Name;
|
||||||
if (site.HomePageId != null)
|
if (site.HomePageId != null)
|
||||||
{
|
{
|
||||||
@ -480,23 +514,23 @@
|
|||||||
_containertype = (!string.IsNullOrEmpty(site.DefaultContainerType)) ? site.DefaultContainerType : Constants.DefaultContainer;
|
_containertype = (!string.IsNullOrEmpty(site.DefaultContainerType)) ? site.DefaultContainerType : Constants.DefaultContainer;
|
||||||
_admincontainertype = (!string.IsNullOrEmpty(site.AdminContainerType)) ? site.AdminContainerType : Constants.DefaultAdminContainer;
|
_admincontainertype = (!string.IsNullOrEmpty(site.AdminContainerType)) ? site.AdminContainerType : Constants.DefaultAdminContainer;
|
||||||
|
|
||||||
|
// functionality
|
||||||
|
var textEditors = ServiceProvider.GetServices<ITextEditor>();
|
||||||
|
foreach (var textEditor in textEditors)
|
||||||
|
{
|
||||||
|
_textEditors.Add(textEditor.Name, Utilities.GetFullTypeName(textEditor.GetType().AssemblyQualifiedName));
|
||||||
|
}
|
||||||
|
_textEditor = SettingService.GetSetting(settings, "TextEditor", Constants.DefaultTextEditor);
|
||||||
|
_imageFiles = SettingService.GetSetting(settings, "ImageFiles", Constants.ImageFiles);
|
||||||
|
_imageFiles = (string.IsNullOrEmpty(_imageFiles)) ? Constants.ImageFiles : _imageFiles;
|
||||||
|
_uploadableFiles = SettingService.GetSetting(settings, "UploadableFiles", Constants.UploadableFiles);
|
||||||
|
_uploadableFiles = (string.IsNullOrEmpty(_uploadableFiles)) ? Constants.UploadableFiles : _uploadableFiles;
|
||||||
|
|
||||||
// page content
|
// page content
|
||||||
_headcontent = site.HeadContent;
|
_headcontent = site.HeadContent;
|
||||||
_bodycontent = site.BodyContent;
|
_bodycontent = site.BodyContent;
|
||||||
|
|
||||||
// PWA
|
|
||||||
_pwaisenabled = site.PwaIsEnabled.ToString();
|
|
||||||
if (site.PwaAppIconFileId != null)
|
|
||||||
{
|
|
||||||
_pwaappiconfileid = site.PwaAppIconFileId.Value;
|
|
||||||
}
|
|
||||||
if (site.PwaSplashIconFileId != null)
|
|
||||||
{
|
|
||||||
_pwasplashiconfileid = site.PwaSplashIconFileId.Value;
|
|
||||||
}
|
|
||||||
|
|
||||||
// SMTP
|
// SMTP
|
||||||
var settings = await SettingService.GetSiteSettingsAsync(site.SiteId);
|
|
||||||
_smtphost = SettingService.GetSetting(settings, "SMTPHost", string.Empty);
|
_smtphost = SettingService.GetSetting(settings, "SMTPHost", string.Empty);
|
||||||
_smtpport = SettingService.GetSetting(settings, "SMTPPort", string.Empty);
|
_smtpport = SettingService.GetSetting(settings, "SMTPPort", string.Empty);
|
||||||
_smtpssl = SettingService.GetSetting(settings, "SMTPSSL", "False");
|
_smtpssl = SettingService.GetSetting(settings, "SMTPSSL", "False");
|
||||||
@ -508,11 +542,16 @@
|
|||||||
_smtpenabled = SettingService.GetSetting(settings, "SMTPEnabled", "True");
|
_smtpenabled = SettingService.GetSetting(settings, "SMTPEnabled", "True");
|
||||||
_retention = int.Parse(SettingService.GetSetting(settings, "NotificationRetention", "30"));
|
_retention = int.Parse(SettingService.GetSetting(settings, "NotificationRetention", "30"));
|
||||||
|
|
||||||
// file extensions
|
// PWA
|
||||||
_ImageFiles = SettingService.GetSetting(settings, "ImageFiles", Constants.ImageFiles);
|
_pwaisenabled = site.PwaIsEnabled.ToString();
|
||||||
_ImageFiles = (string.IsNullOrEmpty(_ImageFiles)) ? Constants.ImageFiles : _ImageFiles;
|
if (site.PwaAppIconFileId != null)
|
||||||
_UploadableFiles = SettingService.GetSetting(settings, "UploadableFiles", Constants.UploadableFiles);
|
{
|
||||||
_UploadableFiles = (string.IsNullOrEmpty(_UploadableFiles)) ? Constants.UploadableFiles : _UploadableFiles;
|
_pwaappiconfileid = site.PwaAppIconFileId.Value;
|
||||||
|
}
|
||||||
|
if (site.PwaSplashIconFileId != null)
|
||||||
|
{
|
||||||
|
_pwasplashiconfileid = site.PwaSplashIconFileId.Value;
|
||||||
|
}
|
||||||
|
|
||||||
// aliases
|
// aliases
|
||||||
await GetAliases();
|
await GetAliases();
|
||||||
@ -572,6 +611,23 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void RenderModeChanged(ChangeEventArgs e)
|
||||||
|
{
|
||||||
|
_rendermode = (string)e.Value;
|
||||||
|
switch (_rendermode)
|
||||||
|
{
|
||||||
|
case RenderModes.Interactive:
|
||||||
|
_prerender = "True";
|
||||||
|
break;
|
||||||
|
case RenderModes.Static:
|
||||||
|
_prerender = "False";
|
||||||
|
break;
|
||||||
|
case RenderModes.Headless:
|
||||||
|
_prerender = "False";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private async Task SaveSite()
|
private async Task SaveSite()
|
||||||
{
|
{
|
||||||
validated = true;
|
validated = true;
|
||||||
@ -671,9 +727,10 @@
|
|||||||
settings = SettingService.SetSetting(settings, "SiteGuid", _siteguid, true);
|
settings = SettingService.SetSetting(settings, "SiteGuid", _siteguid, true);
|
||||||
settings = SettingService.SetSetting(settings, "NotificationRetention", _retention.ToString(), true);
|
settings = SettingService.SetSetting(settings, "NotificationRetention", _retention.ToString(), true);
|
||||||
|
|
||||||
// file extensions
|
// functionality
|
||||||
settings = SettingService.SetSetting(settings, "ImageFiles", (_ImageFiles != Constants.ImageFiles) ? _ImageFiles.Replace(" ", "") : "", false);
|
settings = SettingService.SetSetting(settings, "TextEditor", _textEditor);
|
||||||
settings = SettingService.SetSetting(settings, "UploadableFiles", (_UploadableFiles != Constants.UploadableFiles) ? _UploadableFiles.Replace(" ", "") : "", false);
|
settings = SettingService.SetSetting(settings, "ImageFiles", (_imageFiles != Constants.ImageFiles) ? _imageFiles.Replace(" ", "") : "", false);
|
||||||
|
settings = SettingService.SetSetting(settings, "UploadableFiles", (_uploadableFiles != Constants.UploadableFiles) ? _uploadableFiles.Replace(" ", "") : "", false);
|
||||||
|
|
||||||
await SettingService.UpdateSiteSettingsAsync(settings, site.SiteId);
|
await SettingService.UpdateSiteSettingsAsync(settings, site.SiteId);
|
||||||
|
|
||||||
|
@ -125,7 +125,7 @@
|
|||||||
<TabPanel Name="Upload" ResourceKey="Upload">
|
<TabPanel Name="Upload" ResourceKey="Upload">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="row mb-1 align-items-center">
|
<div class="row mb-1 align-items-center">
|
||||||
<Label Class="col-sm-3" HelpText="Upload one or more theme packages. Once they are uploaded click Install to complete the installation." ResourceKey="Theme">Theme: </Label>
|
<Label Class="col-sm-3" HelpText="Upload one or more theme packages." ResourceKey="Theme">Theme: </Label>
|
||||||
<div class="col-sm-9">
|
<div class="col-sm-9">
|
||||||
<FileManager Folder="@Constants.PackagesFolder" UploadMultiple="true" OnUpload="OnUpload" />
|
<FileManager Folder="@Constants.PackagesFolder" UploadMultiple="true" OnUpload="OnUpload" />
|
||||||
</div>
|
</div>
|
||||||
|
@ -29,7 +29,7 @@ else
|
|||||||
<th> </th>
|
<th> </th>
|
||||||
</Header>
|
</Header>
|
||||||
<Row>
|
<Row>
|
||||||
<td><ActionLink Action="Edit" Parameters="@($"id=" + context.ThemeId.ToString())" ResourceKey="EditTheme" /></td>
|
<td><ActionLink Action="Edit" Text="Edit" Parameters="@($"id=" + context.ThemeId.ToString())" ResourceKey="EditTheme" /></td>
|
||||||
<td>
|
<td>
|
||||||
@if (context.AssemblyName != Constants.ClientId)
|
@if (context.AssemblyName != Constants.ClientId)
|
||||||
{
|
{
|
||||||
@ -63,7 +63,6 @@ else
|
|||||||
<button type="button" class="btn btn-success" @onclick=@(async () => await DownloadTheme(context.PackageName, version))>@SharedLocalizer["Upgrade"]</button>
|
<button type="button" class="btn btn-success" @onclick=@(async () => await DownloadTheme(context.PackageName, version))>@SharedLocalizer["Upgrade"]</button>
|
||||||
}
|
}
|
||||||
</td>
|
</td>
|
||||||
<td></td>
|
|
||||||
</Row>
|
</Row>
|
||||||
</Pager>
|
</Pager>
|
||||||
}
|
}
|
||||||
|
@ -37,7 +37,7 @@ else
|
|||||||
<th>@Localizer["Requested"]</th>
|
<th>@Localizer["Requested"]</th>
|
||||||
</Header>
|
</Header>
|
||||||
<Row>
|
<Row>
|
||||||
<td><ActionLink Action="Edit" Parameters="@($"id=" + context.UrlMappingId.ToString())" ResourceKey="Edit" /></td>
|
<td><ActionLink Action="Edit" Text="Edit" Parameters="@($"id=" + context.UrlMappingId.ToString())" ResourceKey="Edit" /></td>
|
||||||
<td><ActionDialog Header="Delete Url Mapping" Message="@string.Format(Localizer["Confirm.DeleteUrlMapping"], context.Url)" Action="Delete" Security="SecurityAccessLevel.Admin" Class="btn btn-danger" OnClick="@(async () => await DeleteUrlMapping(context))" ResourceKey="DeleteUrlMapping" /></td>
|
<td><ActionDialog Header="Delete Url Mapping" Message="@string.Format(Localizer["Confirm.DeleteUrlMapping"], context.Url)" Action="Delete" Security="SecurityAccessLevel.Admin" Class="btn btn-danger" OnClick="@(async () => await DeleteUrlMapping(context))" ResourceKey="DeleteUrlMapping" /></td>
|
||||||
<td>
|
<td>
|
||||||
<a href="@Utilities.TenantUrl(PageState.Alias, context.Url)">@context.Url</a>
|
<a href="@Utilities.TenantUrl(PageState.Alias, context.Url)">@context.Url</a>
|
||||||
|
@ -226,11 +226,6 @@
|
|||||||
user.Password = _password;
|
user.Password = _password;
|
||||||
user.Email = email;
|
user.Email = email;
|
||||||
user.DisplayName = string.IsNullOrWhiteSpace(displayname) ? username : displayname;
|
user.DisplayName = string.IsNullOrWhiteSpace(displayname) ? username : displayname;
|
||||||
user.PhotoFileId = null;
|
|
||||||
if (user.PhotoFileId == -1)
|
|
||||||
{
|
|
||||||
user.PhotoFileId = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
user.IsDeleted = (isdeleted == null ? true : Boolean.Parse(isdeleted));
|
user.IsDeleted = (isdeleted == null ? true : Boolean.Parse(isdeleted));
|
||||||
|
|
||||||
|
@ -32,13 +32,13 @@ else
|
|||||||
</Header>
|
</Header>
|
||||||
<Row>
|
<Row>
|
||||||
<td>
|
<td>
|
||||||
<ActionLink Action="Edit" Parameters="@($"id=" + context.UserId.ToString())" Security="SecurityAccessLevel.Edit" ResourceKey="EditUser" />
|
<ActionLink Action="Edit" Text="Edit" Parameters="@($"id=" + context.UserId.ToString())" Security="SecurityAccessLevel.Edit" ResourceKey="EditUser" />
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<ActionDialog Header="Delete User" Message="@string.Format(Localizer["Confirm.User.Delete"], context.User.DisplayName)" Action="Delete" Security="SecurityAccessLevel.Edit" Class="btn btn-danger" OnClick="@(async () => await DeleteUser(context))" Disabled="@(context.UserId == PageState.User.UserId)" ResourceKey="DeleteUser" />
|
<ActionDialog Header="Delete User" Message="@string.Format(Localizer["Confirm.User.Delete"], context.User.DisplayName)" Action="Delete" Security="SecurityAccessLevel.Edit" Class="btn btn-danger" OnClick="@(async () => await DeleteUser(context))" Disabled="@(context.UserId == PageState.User.UserId)" ResourceKey="DeleteUser" />
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<ActionLink Action="Roles" Parameters="@($"id=" + context.UserId.ToString())" Security="SecurityAccessLevel.Edit" ResourceKey="Roles" />
|
<ActionLink Action="Roles" Text="Roles" Parameters="@($"id=" + context.UserId.ToString())" Security="SecurityAccessLevel.Edit" ResourceKey="Roles" />
|
||||||
</td>
|
</td>
|
||||||
<td>@context.User.Username</td>
|
<td>@context.User.Username</td>
|
||||||
<td>@context.User.DisplayName</td>
|
<td>@context.User.DisplayName</td>
|
||||||
|
@ -43,7 +43,7 @@ else
|
|||||||
<th>@Localizer["Created"]</th>
|
<th>@Localizer["Created"]</th>
|
||||||
</Header>
|
</Header>
|
||||||
<Row>
|
<Row>
|
||||||
<td><ActionLink Action="Detail" Parameters="@($"id={context.VisitorId}")" ReturnUrl="@(NavigateUrl(PageState.Page.Path, $"type={_type}&days={_days}&page={_page}"))" ResourceKey="Details" /></td>
|
<td><ActionLink Action="Detail" Text="Detail" Parameters="@($"id={context.VisitorId}")" ReturnUrl="@(NavigateUrl(PageState.Page.Path, $"type={_type}&days={_days}&page={_page}"))" ResourceKey="Details" /></td>
|
||||||
<td>@context.IPAddress</td>
|
<td>@context.IPAddress</td>
|
||||||
<td>
|
<td>
|
||||||
@if (context.UserId != null)
|
@if (context.UserId != null)
|
||||||
@ -69,6 +69,12 @@ else
|
|||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="row mb-1 align-items-center">
|
||||||
|
<Label Class="col-sm-3" For="duration" HelpText="The duration of a browsing session considered to be a distinct visit (in minutes)" ResourceKey="Duration">Session Duration: </Label>
|
||||||
|
<div class="col-sm-9">
|
||||||
|
<input id="duration" class="form-control" type="number" min="0" step="1" @bind="@_duration" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div class="row mb-1 align-items-center">
|
<div class="row mb-1 align-items-center">
|
||||||
<Label Class="col-sm-3" For="filter" HelpText="Comma delimited list of terms which may exist in IP addresses, user agents, or languages identifying visitors which should not be tracked" ResourceKey="Filter">Filter: </Label>
|
<Label Class="col-sm-3" For="filter" HelpText="Comma delimited list of terms which may exist in IP addresses, user agents, or languages identifying visitors which should not be tracked" ResourceKey="Filter">Filter: </Label>
|
||||||
<div class="col-sm-9">
|
<div class="col-sm-9">
|
||||||
@ -76,7 +82,7 @@ else
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row mb-1 align-items-center">
|
<div class="row mb-1 align-items-center">
|
||||||
<Label Class="col-sm-3" For="retention" HelpText="Number of days of visitor activity to retain" ResourceKey="Retention">Retention (Days): </Label>
|
<Label Class="col-sm-3" For="retention" HelpText="Number of days of visitor activity to retain" ResourceKey="Retention">Retention: </Label>
|
||||||
<div class="col-sm-9">
|
<div class="col-sm-9">
|
||||||
<input id="retention" class="form-control" type="number" min="0" step="1" @bind="@_retention" />
|
<input id="retention" class="form-control" type="number" min="0" step="1" @bind="@_retention" />
|
||||||
</div>
|
</div>
|
||||||
@ -103,6 +109,7 @@ else
|
|||||||
private int _page = 1;
|
private int _page = 1;
|
||||||
private List<Visitor> _visitors;
|
private List<Visitor> _visitors;
|
||||||
private string _tracking;
|
private string _tracking;
|
||||||
|
private int _duration = 5;
|
||||||
private string _filter = "";
|
private string _filter = "";
|
||||||
private int _retention = 30;
|
private int _retention = 30;
|
||||||
private string _correlation = "true";
|
private string _correlation = "true";
|
||||||
@ -128,6 +135,7 @@ else
|
|||||||
|
|
||||||
_tracking = PageState.Site.VisitorTracking.ToString();
|
_tracking = PageState.Site.VisitorTracking.ToString();
|
||||||
var settings = await SettingService.GetSiteSettingsAsync(PageState.Site.SiteId);
|
var settings = await SettingService.GetSiteSettingsAsync(PageState.Site.SiteId);
|
||||||
|
_duration = int.Parse(SettingService.GetSetting(settings, "VisitorDuration", "5"));
|
||||||
_filter = SettingService.GetSetting(settings, "VisitorFilter", Constants.DefaultVisitorFilter);
|
_filter = SettingService.GetSetting(settings, "VisitorFilter", Constants.DefaultVisitorFilter);
|
||||||
_retention = int.Parse(SettingService.GetSetting(settings, "VisitorRetention", "30"));
|
_retention = int.Parse(SettingService.GetSetting(settings, "VisitorRetention", "30"));
|
||||||
_correlation = SettingService.GetSetting(settings, "VisitorCorrelation", "true");
|
_correlation = SettingService.GetSetting(settings, "VisitorCorrelation", "true");
|
||||||
@ -179,6 +187,7 @@ else
|
|||||||
await SiteService.UpdateSiteAsync(site);
|
await SiteService.UpdateSiteAsync(site);
|
||||||
|
|
||||||
var settings = await SettingService.GetSiteSettingsAsync(PageState.Site.SiteId);
|
var settings = await SettingService.GetSiteSettingsAsync(PageState.Site.SiteId);
|
||||||
|
settings = SettingService.SetSetting(settings, "VisitorDuration", _duration.ToString(), true);
|
||||||
settings = SettingService.SetSetting(settings, "VisitorFilter", _filter, true);
|
settings = SettingService.SetSetting(settings, "VisitorFilter", _filter, true);
|
||||||
settings = SettingService.SetSetting(settings, "VisitorRetention", _retention.ToString(), true);
|
settings = SettingService.SetSetting(settings, "VisitorRetention", _retention.ToString(), true);
|
||||||
settings = SettingService.SetSetting(settings, "VisitorCorrelation", _correlation, true);
|
settings = SettingService.SetSetting(settings, "VisitorCorrelation", _correlation, true);
|
||||||
|
@ -35,11 +35,11 @@
|
|||||||
{
|
{
|
||||||
if (Disabled)
|
if (Disabled)
|
||||||
{
|
{
|
||||||
<button type="button" class="@Class" disabled>@((MarkupString)_iconSpan) @Text</button>
|
<button type="button" class="@Class" disabled>@((MarkupString)_openIconSpan) @_openText</button>
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
<button type="button" class="@Class" @onclick="DisplayModal">@((MarkupString)_iconSpan) @Text</button>
|
<button type="button" class="@Class" @onclick="DisplayModal">@((MarkupString)_openIconSpan) @_openText</button>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -51,25 +51,25 @@ else
|
|||||||
<div class="modal" tabindex="-1" role="dialog">
|
<div class="modal" tabindex="-1" role="dialog">
|
||||||
<div class="modal-dialog">
|
<div class="modal-dialog">
|
||||||
<div class="modal-content">
|
<div class="modal-content">
|
||||||
|
<form class="app-form-inline" method="post" @formname="@($"ActionDialogCloseForm:{ModuleState.PageModuleId}:{Id}")" @onsubmit="DisplayModal" data-enhance>
|
||||||
|
<input type="hidden" name="@Constants.RequestVerificationToken" value="@SiteState.AntiForgeryToken" />
|
||||||
<div class="modal-header">
|
<div class="modal-header">
|
||||||
<h5 class="modal-title">@Header</h5>
|
<h5 class="modal-title">@Header</h5>
|
||||||
<form method="post" @formname="@($"ActionDialogCloseForm{Id}")" @onsubmit="DisplayModal" data-enhance>
|
|
||||||
<input type="hidden" name="@Constants.RequestVerificationToken" value="@SiteState.AntiForgeryToken" />
|
|
||||||
<button type="submit" class="btn-close" aria-label="Close"></button>
|
<button type="submit" class="btn-close" aria-label="Close"></button>
|
||||||
</form>
|
|
||||||
</div>
|
</div>
|
||||||
|
</form>
|
||||||
<div class="modal-body">
|
<div class="modal-body">
|
||||||
<p>@Message</p>
|
<p>@Message</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-footer">
|
<div class="modal-footer">
|
||||||
@if (!string.IsNullOrEmpty(Action))
|
@if (!string.IsNullOrEmpty(Action))
|
||||||
{
|
{
|
||||||
<form method="post" @formname="@($"ActionDialogConfirmForm{Id}")" @onsubmit="Confirm" data-enhance>
|
<form method="post" @formname="@($"ActionDialogConfirmForm:{ModuleState.PageModuleId}:{Id}")" @onsubmit="Confirm" data-enhance>
|
||||||
<input type="hidden" name="@Constants.RequestVerificationToken" value="@SiteState.AntiForgeryToken" />
|
<input type="hidden" name="@Constants.RequestVerificationToken" value="@SiteState.AntiForgeryToken" />
|
||||||
<button type="submit" class="@Class">@((MarkupString)_iconSpan) @Text</button>
|
<button type="submit" class="@Class">@((MarkupString)_iconSpan) @Text</button>
|
||||||
</form>
|
</form>
|
||||||
}
|
}
|
||||||
<form method="post" @formname="@($"ActionDialogCancelForm{Id}")" @onsubmit="DisplayModal" data-enhance>
|
<form method="post" @formname="@($"ActionDialogCancelForm:{ModuleState.PageModuleId}:{Id}")" @onsubmit="DisplayModal" data-enhance>
|
||||||
<input type="hidden" name="@Constants.RequestVerificationToken" value="@SiteState.AntiForgeryToken" />
|
<input type="hidden" name="@Constants.RequestVerificationToken" value="@SiteState.AntiForgeryToken" />
|
||||||
<button type="submit" class="btn btn-secondary">@SharedLocalizer["Cancel"]</button>
|
<button type="submit" class="btn btn-secondary">@SharedLocalizer["Cancel"]</button>
|
||||||
</form>
|
</form>
|
||||||
@ -83,13 +83,13 @@ else
|
|||||||
{
|
{
|
||||||
if (Disabled)
|
if (Disabled)
|
||||||
{
|
{
|
||||||
<button type="button" class="@Class" disabled>@((MarkupString)_iconSpan) @Text</button>
|
<button type="button" class="@Class" disabled>@((MarkupString)_openIconSpan) @_openText</button>
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
<form method="post" @formname="@($"ActionDialogActionForm{Id}")" @onsubmit="DisplayModal" data-enhance>
|
<form method="post" class="app-form-inline" @formname="@($"ActionDialogActionForm:{ModuleState.PageModuleId}:{Id}")" @onsubmit="DisplayModal" data-enhance>
|
||||||
<input type="hidden" name="@Constants.RequestVerificationToken" value="@SiteState.AntiForgeryToken" />
|
<input type="hidden" name="@Constants.RequestVerificationToken" value="@SiteState.AntiForgeryToken" />
|
||||||
<button type="submit" class="@Class">@((MarkupString)_iconSpan) @Text</button>
|
<button type="submit" class="@Class">@((MarkupString)_openIconSpan) @_openText</button>
|
||||||
</form>
|
</form>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -101,6 +101,8 @@ else
|
|||||||
private bool _editmode = false;
|
private bool _editmode = false;
|
||||||
private bool _authorized = false;
|
private bool _authorized = false;
|
||||||
private string _iconSpan = string.Empty;
|
private string _iconSpan = string.Empty;
|
||||||
|
private string _openIconSpan = string.Empty;
|
||||||
|
private string _openText = string.Empty;
|
||||||
|
|
||||||
[Parameter]
|
[Parameter]
|
||||||
public string Header { get; set; } // required
|
public string Header { get; set; } // required
|
||||||
@ -138,6 +140,9 @@ else
|
|||||||
[Parameter]
|
[Parameter]
|
||||||
public string IconName { get; set; } // optional - specifies an icon for the link - default is no icon
|
public string IconName { get; set; } // optional - specifies an icon for the link - default is no icon
|
||||||
|
|
||||||
|
[Parameter]
|
||||||
|
public bool IconOnly { get; set; } // optional - specifies only icon in opening link
|
||||||
|
|
||||||
[Parameter]
|
[Parameter]
|
||||||
public string Id { get; set; } // optional - specifies a unique id for the compoment - required when there are multiple component instances on a page in static rendering
|
public string Id { get; set; } // optional - specifies a unique id for the compoment - required when there are multiple component instances on a page in static rendering
|
||||||
|
|
||||||
@ -157,6 +162,7 @@ else
|
|||||||
{
|
{
|
||||||
Text = Action;
|
Text = Action;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (string.IsNullOrEmpty(Class))
|
if (string.IsNullOrEmpty(Class))
|
||||||
{
|
{
|
||||||
Class = "btn btn-success";
|
Class = "btn btn-success";
|
||||||
@ -169,20 +175,32 @@ else
|
|||||||
|
|
||||||
if (!string.IsNullOrEmpty(IconName))
|
if (!string.IsNullOrEmpty(IconName))
|
||||||
{
|
{
|
||||||
if (!IconName.Contains(" "))
|
if (IconOnly)
|
||||||
|
{
|
||||||
|
_openText = string.Empty;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if IconName starts with "oi oi-"
|
||||||
|
bool startsWithOiOi = IconName.StartsWith("oi oi-");
|
||||||
|
|
||||||
|
if (!startsWithOiOi && !IconName.Contains(" "))
|
||||||
{
|
{
|
||||||
IconName = "oi oi-" + IconName;
|
IconName = "oi oi-" + IconName;
|
||||||
}
|
}
|
||||||
_iconSpan = $"<span class=\"{IconName}\"></span> ";
|
_openIconSpan = $"<span class=\"{IconName}\"></span>{(IconOnly ? "" : " ")}";
|
||||||
|
_iconSpan = $"<span class=\"{IconName}\"></span> ";
|
||||||
}
|
}
|
||||||
|
|
||||||
Text = Localize(nameof(Text), Text);
|
Text = Localize(nameof(Text), Text);
|
||||||
Header = Localize(nameof(Header), Header);
|
Header = Localize(nameof(Header), Header);
|
||||||
Message = Localize(nameof(Message), Message);
|
Message = Localize(nameof(Message), Message);
|
||||||
|
|
||||||
|
_openText = Text;
|
||||||
_permissions = (PermissionList == null) ? ModuleState.PermissionList : PermissionList;
|
_permissions = (PermissionList == null) ? ModuleState.PermissionList : PermissionList;
|
||||||
_authorized = IsAuthorized();
|
_authorized = IsAuthorized();
|
||||||
|
|
||||||
|
if (string.IsNullOrEmpty(Id)) Id = "1";
|
||||||
|
|
||||||
if (PageState.QueryString.ContainsKey("dialog"))
|
if (PageState.QueryString.ContainsKey("dialog"))
|
||||||
{
|
{
|
||||||
_visible = (PageState.QueryString["dialog"] == Id);
|
_visible = (PageState.QueryString["dialog"] == Id);
|
||||||
|
@ -145,7 +145,10 @@
|
|||||||
|
|
||||||
if (!string.IsNullOrEmpty(IconName))
|
if (!string.IsNullOrEmpty(IconName))
|
||||||
{
|
{
|
||||||
if (!IconName.Contains(" "))
|
// Check if IconName starts with "oi oi-"
|
||||||
|
bool startsWithOiOi = IconName.StartsWith("oi oi-");
|
||||||
|
|
||||||
|
if (!startsWithOiOi && !IconName.Contains(" "))
|
||||||
{
|
{
|
||||||
IconName = "oi oi-" + IconName;
|
IconName = "oi oi-" + IconName;
|
||||||
}
|
}
|
||||||
|
@ -314,7 +314,6 @@
|
|||||||
await SetImage();
|
await SetImage();
|
||||||
await OnSelect.InvokeAsync(FileId);
|
await OnSelect.InvokeAsync(FileId);
|
||||||
StateHasChanged();
|
StateHasChanged();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task SetImage()
|
private async Task SetImage()
|
||||||
|
@ -37,8 +37,6 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected void OnChange(ChangeEventArgs e)
|
protected void OnChange(ChangeEventArgs e)
|
||||||
{
|
|
||||||
if (!string.IsNullOrEmpty(e.Value.ToString()))
|
|
||||||
{
|
{
|
||||||
Value = e.Value.ToString();
|
Value = e.Value.ToString();
|
||||||
if (ValueChanged.HasDelegate)
|
if (ValueChanged.HasDelegate)
|
||||||
@ -46,5 +44,4 @@
|
|||||||
ValueChanged.InvokeAsync(Value);
|
ValueChanged.InvokeAsync(Value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
@ -6,23 +6,24 @@
|
|||||||
{
|
{
|
||||||
<div class="@_classname alert-dismissible fade show mb-3" role="alert">
|
<div class="@_classname alert-dismissible fade show mb-3" role="alert">
|
||||||
@((MarkupString)Message)
|
@((MarkupString)Message)
|
||||||
@if (PageState != null)
|
@if (Type == MessageType.Error && PageState != null && UserSecurity.IsAuthorized(PageState.User, RoleNames.Host))
|
||||||
{
|
|
||||||
@if (Type == MessageType.Error && UserSecurity.IsAuthorized(PageState.User, RoleNames.Host))
|
|
||||||
{
|
{
|
||||||
<NavLink class="ms-2" href="@NavigateUrl("admin/log")">View Details</NavLink>
|
<NavLink class="ms-2" href="@NavigateUrl("admin/log")">View Details</NavLink>
|
||||||
}
|
}
|
||||||
<form method="post" @onsubmit="DismissModal" @formname="@_formname" data-enhance>
|
@if (ModuleState.RenderMode == RenderModes.Static)
|
||||||
<input type="hidden" name="@Constants.RequestVerificationToken" value="@SiteState.AntiForgeryToken" />
|
{
|
||||||
<button type="submit" class="btn-close" aria-label="Close"></button>
|
<a href="@NavigationManager.Uri" class="btn-close" data-dismiss="alert" aria-label="close"></a>
|
||||||
</form>
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
<button type="button" class="btn-close" data-dismiss="alert" aria-label="close" @onclick="CloseMessage"></button>
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
|
||||||
@code {
|
@code {
|
||||||
|
private string _message = string.Empty;
|
||||||
private string _classname = string.Empty;
|
private string _classname = string.Empty;
|
||||||
private string _formname = "ModuleMessageForm";
|
|
||||||
|
|
||||||
[Parameter]
|
[Parameter]
|
||||||
public string Message { get; set; }
|
public string Message { get; set; }
|
||||||
@ -30,32 +31,13 @@
|
|||||||
[Parameter]
|
[Parameter]
|
||||||
public MessageType Type { get; set; }
|
public MessageType Type { get; set; }
|
||||||
|
|
||||||
public void RefreshMessage(string message, MessageType type)
|
[Parameter]
|
||||||
{
|
public RenderModeBoundary Parent { get; set; }
|
||||||
Message = message;
|
|
||||||
Type = type;
|
|
||||||
|
|
||||||
UpdateClassName();
|
|
||||||
|
|
||||||
StateHasChanged();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void OnInitialized()
|
|
||||||
{
|
|
||||||
if (ModuleState != null)
|
|
||||||
{
|
|
||||||
_formname += ModuleState.PageModuleId.ToString();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void OnParametersSet()
|
protected override void OnParametersSet()
|
||||||
{
|
{
|
||||||
UpdateClassName();
|
_message = Message;
|
||||||
}
|
if (!string.IsNullOrEmpty(_message))
|
||||||
|
|
||||||
private void UpdateClassName()
|
|
||||||
{
|
|
||||||
if (!string.IsNullOrEmpty(Message))
|
|
||||||
{
|
{
|
||||||
_classname = GetMessageType(Type);
|
_classname = GetMessageType(Type);
|
||||||
}
|
}
|
||||||
@ -82,9 +64,15 @@
|
|||||||
|
|
||||||
return classname;
|
return classname;
|
||||||
}
|
}
|
||||||
|
private void CloseMessage(MouseEventArgs e)
|
||||||
private void DismissModal()
|
|
||||||
{
|
{
|
||||||
Message = "";
|
if(Parent != null)
|
||||||
|
{
|
||||||
|
Parent.DismissMessage();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
NavigationManager.NavigateTo(NavigationManager.Uri);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -11,7 +11,7 @@
|
|||||||
@if (!string.IsNullOrEmpty(SearchProperties))
|
@if (!string.IsNullOrEmpty(SearchProperties))
|
||||||
{
|
{
|
||||||
<form autocomplete="off">
|
<form autocomplete="off">
|
||||||
<div class="input-group my-3">
|
<div class="input-group my-3 @SearchBoxClass">
|
||||||
<input type="text" id="pagersearch" class="form-control" placeholder=@string.Format(Localizer["SearchPlaceholder"], FormatSearchProperties()) @bind="@_search" />
|
<input type="text" id="pagersearch" class="form-control" placeholder=@string.Format(Localizer["SearchPlaceholder"], FormatSearchProperties()) @bind="@_search" />
|
||||||
<button type="button" class="btn btn-primary" @onclick="Search">@SharedLocalizer["Search"]</button>
|
<button type="button" class="btn btn-primary" @onclick="Search">@SharedLocalizer["Search"]</button>
|
||||||
<button type="button" class="btn btn-secondary" @onclick="Reset">@SharedLocalizer["Reset"]</button>
|
<button type="button" class="btn btn-secondary" @onclick="Reset">@SharedLocalizer["Reset"]</button>
|
||||||
@ -23,16 +23,16 @@
|
|||||||
{
|
{
|
||||||
<ul class="pagination justify-content-center my-2">
|
<ul class="pagination justify-content-center my-2">
|
||||||
<li class="page-item@((_page > 1) ? " app-pager-pointer" : " disabled")">
|
<li class="page-item@((_page > 1) ? " app-pager-pointer" : " disabled")">
|
||||||
<a class="page-link" @onclick=@(async () => UpdateList(1))><span class="oi oi-media-step-backward" title="start" aria-hidden="true"></span></a>
|
<a class="page-link shadow-none" @onclick=@(async () => UpdateList(1))><span class="oi oi-media-step-backward" title="start" aria-hidden="true"></span></a>
|
||||||
</li>
|
</li>
|
||||||
@if (_pages > _displayPages && _displayPages > 1)
|
@if (_pages > _displayPages && _displayPages > 1)
|
||||||
{
|
{
|
||||||
<li class="page-item@((_page > _displayPages) ? " app-pager-pointer" : " disabled")">
|
<li class="page-item@((_page > _displayPages) ? " app-pager-pointer" : " disabled")">
|
||||||
<a class="page-link" @onclick=@(async () => SkipPages("back"))><span class="oi oi-media-skip-backward" title="skip back" aria-hidden="true"></span></a>
|
<a class="page-link shadow-none" @onclick=@(async () => SkipPages("back"))><span class="oi oi-media-skip-backward" title="skip back" aria-hidden="true"></span></a>
|
||||||
</li>
|
</li>
|
||||||
}
|
}
|
||||||
<li class="page-item@((_page > 1) ? " app-pager-pointer" : " disabled")">
|
<li class="page-item@((_page > 1) ? " app-pager-pointer" : " disabled")">
|
||||||
<a class="page-link" @onclick=@(async () => NavigateToPage("previous"))><span class="oi oi-chevron-left" title="previous" aria-hidden="true"></span></a>
|
<a class="page-link shadow-none" @onclick=@(async () => NavigateToPage("previous"))><span class="oi oi-chevron-left" title="previous" aria-hidden="true"></span></a>
|
||||||
</li>
|
</li>
|
||||||
@for (int i = _startPage; i <= _endPage; i++)
|
@for (int i = _startPage; i <= _endPage; i++)
|
||||||
{
|
{
|
||||||
@ -40,30 +40,30 @@
|
|||||||
if (pager == _page)
|
if (pager == _page)
|
||||||
{
|
{
|
||||||
<li class="page-item app-pager-pointer active">
|
<li class="page-item app-pager-pointer active">
|
||||||
<a class="page-link" @onclick=@(async () => UpdateList(pager))>@pager</a>
|
<a class="page-link shadow-none" @onclick=@(async () => UpdateList(pager))>@pager</a>
|
||||||
</li>
|
</li>
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
<li class="page-item app-pager-pointer">
|
<li class="page-item app-pager-pointer">
|
||||||
<a class="page-link" @onclick=@(async () => UpdateList(pager))>@pager</a>
|
<a class="page-link shadow-none" @onclick=@(async () => UpdateList(pager))>@pager</a>
|
||||||
</li>
|
</li>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
<li class="page-item@((_page < _pages) ? " app-pager-pointer" : " disabled")">
|
<li class="page-item@((_page < _pages) ? " app-pager-pointer" : " disabled")">
|
||||||
<a class="page-link" @onclick=@(async () => NavigateToPage("next"))><span class="oi oi-chevron-right" title="next" aria-hidden="true"></span></a>
|
<a class="page-link shadow-none" @onclick=@(async () => NavigateToPage("next"))><span class="oi oi-chevron-right" title="next" aria-hidden="true"></span></a>
|
||||||
</li>
|
</li>
|
||||||
@if (_pages > _displayPages && _displayPages > 1)
|
@if (_pages > _displayPages && _displayPages > 1)
|
||||||
{
|
{
|
||||||
<li class="page-item@((_endPage < _pages) ? " app-pager-pointer" : " disabled")">
|
<li class="page-item@((_endPage < _pages) ? " app-pager-pointer" : " disabled")">
|
||||||
<a class="page-link" @onclick=@(async () => SkipPages("forward"))><span class="oi oi-media-skip-forward" title="skip forward" aria-hidden="true"></span></a>
|
<a class="page-link shadow-none" @onclick=@(async () => SkipPages("forward"))><span class="oi oi-media-skip-forward" title="skip forward" aria-hidden="true"></span></a>
|
||||||
</li>
|
</li>
|
||||||
}
|
}
|
||||||
<li class="page-item@((_page < _pages) ? " app-pager-pointer" : " disabled")">
|
<li class="page-item@((_page < _pages) ? " app-pager-pointer" : " disabled")">
|
||||||
<a class="page-link" @onclick=@(async () => UpdateList(_pages))><span class="oi oi-media-step-forward" title="end" aria-hidden="true"></span></a>
|
<a class="page-link shadow-none" @onclick=@(async () => UpdateList(_pages))><span class="oi oi-media-step-forward" title="end" aria-hidden="true"></span></a>
|
||||||
</li>
|
</li>
|
||||||
<li class="page-item disabled">
|
<li class="page-item disabled">
|
||||||
<a class="page-link" style="white-space: nowrap;">@Localizer["PageOfPages", _page, _pages]</a>
|
<a class="page-link shadow-none" style="white-space: nowrap;">@Localizer["PageOfPages", _page, _pages]</a>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
}
|
}
|
||||||
@ -74,7 +74,7 @@
|
|||||||
{
|
{
|
||||||
<form method="post" autocomplete="off" @formname="PagerForm" @onsubmit="Search" data-enhance>
|
<form method="post" autocomplete="off" @formname="PagerForm" @onsubmit="Search" data-enhance>
|
||||||
<input type="hidden" name="@Constants.RequestVerificationToken" value="@SiteState.AntiForgeryToken" />
|
<input type="hidden" name="@Constants.RequestVerificationToken" value="@SiteState.AntiForgeryToken" />
|
||||||
<div class="input-group my-3">
|
<div class="input-group my-3 @SearchBoxClass">
|
||||||
<input type="text" id="pagersearch" name="_search" class="form-control" placeholder=@string.Format(Localizer["SearchPlaceholder"], FormatSearchProperties()) @bind="@_search" />
|
<input type="text" id="pagersearch" name="_search" class="form-control" placeholder=@string.Format(Localizer["SearchPlaceholder"], FormatSearchProperties()) @bind="@_search" />
|
||||||
<button type="submit" class="btn btn-primary">@SharedLocalizer["Search"]</button>
|
<button type="submit" class="btn btn-primary">@SharedLocalizer["Search"]</button>
|
||||||
<a class="btn btn-secondary" href="@PageUrl(1, "")">@SharedLocalizer["Reset"]</a>
|
<a class="btn btn-secondary" href="@PageUrl(1, "")">@SharedLocalizer["Reset"]</a>
|
||||||
@ -86,16 +86,16 @@
|
|||||||
{
|
{
|
||||||
<ul class="pagination justify-content-center my-2">
|
<ul class="pagination justify-content-center my-2">
|
||||||
<li class="page-item@((_page > 1) ? " app-pager-pointer" : " disabled")">
|
<li class="page-item@((_page > 1) ? " app-pager-pointer" : " disabled")">
|
||||||
<a class="page-link" href="@PageUrl(1, _search)"><span class="oi oi-media-step-backward" title="start" aria-hidden="true"></span></a>
|
<a class="page-link shadow-none" href="@PageUrl(1, _search)"><span class="oi oi-media-step-backward" title="start" aria-hidden="true"></span></a>
|
||||||
</li>
|
</li>
|
||||||
@if (_pages > _displayPages && _displayPages > 1)
|
@if (_pages > _displayPages && _displayPages > 1)
|
||||||
{
|
{
|
||||||
<li class="page-item@((_page > _displayPages) ? " app-pager-pointer" : " disabled")">
|
<li class="page-item@((_page > _displayPages) ? " app-pager-pointer" : " disabled")">
|
||||||
<a class="page-link" href="@PageUrl(_startPage - 1, _search)"><span class="oi oi-media-skip-backward" title="skip back" aria-hidden="true"></span></a>
|
<a class="page-link shadow-none" href="@PageUrl(_startPage - 1, _search)"><span class="oi oi-media-skip-backward" title="skip back" aria-hidden="true"></span></a>
|
||||||
</li>
|
</li>
|
||||||
}
|
}
|
||||||
<li class="page-item@((_page > 1) ? " app-pager-pointer" : " disabled")">
|
<li class="page-item@((_page > 1) ? " app-pager-pointer" : " disabled")">
|
||||||
<a class="page-link" href="@PageUrl(((_page > 1) ? _page - 1 : _page), _search)"><span class="oi oi-chevron-left" title="previous" aria-hidden="true"></span></a>
|
<a class="page-link shadow-none" href="@PageUrl(((_page > 1) ? _page - 1 : _page), _search)"><span class="oi oi-chevron-left" title="previous" aria-hidden="true"></span></a>
|
||||||
</li>
|
</li>
|
||||||
@for (int i = _startPage; i <= _endPage; i++)
|
@for (int i = _startPage; i <= _endPage; i++)
|
||||||
{
|
{
|
||||||
@ -103,30 +103,30 @@
|
|||||||
if (pager == _page)
|
if (pager == _page)
|
||||||
{
|
{
|
||||||
<li class="page-item app-pager-pointer active">
|
<li class="page-item app-pager-pointer active">
|
||||||
<a class="page-link" href="@PageUrl(pager, _search)">@pager</a>
|
<a class="page-link shadow-none" href="@PageUrl(pager, _search)">@pager</a>
|
||||||
</li>
|
</li>
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
<li class="page-item app-pager-pointer">
|
<li class="page-item app-pager-pointer">
|
||||||
<a class="page-link" href="@PageUrl(pager, _search)">@pager</a>
|
<a class="page-link shadow-none" href="@PageUrl(pager, _search)">@pager</a>
|
||||||
</li>
|
</li>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
<li class="page-item@((_page < _pages) ? " app-pager-pointer" : " disabled")">
|
<li class="page-item@((_page < _pages) ? " app-pager-pointer" : " disabled")">
|
||||||
<a class="page-link" href="@PageUrl(((_page < _pages) ? _page + 1 : _page), _search)"><span class="oi oi-chevron-right" title="next" aria-hidden="true"></span></a>
|
<a class="page-link shadow-none" href="@PageUrl(((_page < _pages) ? _page + 1 : _page), _search)"><span class="oi oi-chevron-right" title="next" aria-hidden="true"></span></a>
|
||||||
</li>
|
</li>
|
||||||
@if (_pages > _displayPages && _displayPages > 1)
|
@if (_pages > _displayPages && _displayPages > 1)
|
||||||
{
|
{
|
||||||
<li class="page-item@((_endPage < _pages) ? " app-pager-pointer" : " disabled")">
|
<li class="page-item@((_endPage < _pages) ? " app-pager-pointer" : " disabled")">
|
||||||
<a class="page-link" href="@PageUrl(_endPage + 1, _search)"><span class="oi oi-media-skip-forward" title="skip forward" aria-hidden="true"></span></a>
|
<a class="page-link shadow-none" href="@PageUrl(_endPage + 1, _search)"><span class="oi oi-media-skip-forward" title="skip forward" aria-hidden="true"></span></a>
|
||||||
</li>
|
</li>
|
||||||
}
|
}
|
||||||
<li class="page-item@((_page < _pages) ? " app-pager-pointer" : " disabled")">
|
<li class="page-item@((_page < _pages) ? " app-pager-pointer" : " disabled")">
|
||||||
<a class="page-link" href="@PageUrl(_pages, _search)"><span class="oi oi-media-step-forward" title="end" aria-hidden="true"></span></a>
|
<a class="page-link shadow-none" href="@PageUrl(_pages, _search)"><span class="oi oi-media-step-forward" title="end" aria-hidden="true"></span></a>
|
||||||
</li>
|
</li>
|
||||||
<li class="page-item disabled">
|
<li class="page-item disabled">
|
||||||
<a class="page-link" style="white-space: nowrap;">@Localizer["PageOfPages", _page, _pages]</a>
|
<a class="page-link shadow-none" style="white-space: nowrap;">@Localizer["PageOfPages", _page, _pages]</a>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
}
|
}
|
||||||
@ -202,16 +202,16 @@
|
|||||||
{
|
{
|
||||||
<ul class="pagination justify-content-center my-2">
|
<ul class="pagination justify-content-center my-2">
|
||||||
<li class="page-item@((_page > 1) ? " app-pager-pointer" : " disabled")">
|
<li class="page-item@((_page > 1) ? " app-pager-pointer" : " disabled")">
|
||||||
<a class="page-link" @onclick=@(async () => UpdateList(1))><span class="oi oi-media-step-backward" title="start" aria-hidden="true"></span></a>
|
<a class="page-link shadow-none" @onclick=@(async () => UpdateList(1))><span class="oi oi-media-step-backward" title="start" aria-hidden="true"></span></a>
|
||||||
</li>
|
</li>
|
||||||
@if (_pages > _displayPages && _displayPages > 1)
|
@if (_pages > _displayPages && _displayPages > 1)
|
||||||
{
|
{
|
||||||
<li class="page-item@((_page > _displayPages) ? " app-pager-pointer" : " disabled")">
|
<li class="page-item@((_page > _displayPages) ? " app-pager-pointer" : " disabled")">
|
||||||
<a class="page-link" @onclick=@(async () => SkipPages("back"))><span class="oi oi-media-skip-backward" title="skip back" aria-hidden="true"></span></a>
|
<a class="page-link shadow-none" @onclick=@(async () => SkipPages("back"))><span class="oi oi-media-skip-backward" title="skip back" aria-hidden="true"></span></a>
|
||||||
</li>
|
</li>
|
||||||
}
|
}
|
||||||
<li class="page-item@((_page > 1) ? " app-pager-pointer" : " disabled")">
|
<li class="page-item@((_page > 1) ? " app-pager-pointer" : " disabled")">
|
||||||
<a class="page-link" @onclick=@(async () => NavigateToPage("previous"))><span class="oi oi-chevron-left" title="previous" aria-hidden="true"></span></a>
|
<a class="page-link shadow-none" @onclick=@(async () => NavigateToPage("previous"))><span class="oi oi-chevron-left" title="previous" aria-hidden="true"></span></a>
|
||||||
</li>
|
</li>
|
||||||
@for (int i = _startPage; i <= _endPage; i++)
|
@for (int i = _startPage; i <= _endPage; i++)
|
||||||
{
|
{
|
||||||
@ -219,30 +219,30 @@
|
|||||||
if (pager == _page)
|
if (pager == _page)
|
||||||
{
|
{
|
||||||
<li class="page-item app-pager-pointer active">
|
<li class="page-item app-pager-pointer active">
|
||||||
<a class="page-link" @onclick=@(async () => UpdateList(pager))>@pager</a>
|
<a class="page-link shadow-none" @onclick=@(async () => UpdateList(pager))>@pager</a>
|
||||||
</li>
|
</li>
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
<li class="page-item app-pager-pointer">
|
<li class="page-item app-pager-pointer">
|
||||||
<a class="page-link" @onclick=@(async () => UpdateList(pager))>@pager</a>
|
<a class="page-link shadow-none" @onclick=@(async () => UpdateList(pager))>@pager</a>
|
||||||
</li>
|
</li>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
<li class="page-item@((_page < _pages) ? " app-pager-pointer" : " disabled")">
|
<li class="page-item@((_page < _pages) ? " app-pager-pointer" : " disabled")">
|
||||||
<a class="page-link" @onclick=@(async () => NavigateToPage("next"))><span class="oi oi-chevron-right" title="next" aria-hidden="true"></span></a>
|
<a class="page-link shadow-none" @onclick=@(async () => NavigateToPage("next"))><span class="oi oi-chevron-right" title="next" aria-hidden="true"></span></a>
|
||||||
</li>
|
</li>
|
||||||
@if (_pages > _displayPages && _displayPages > 1)
|
@if (_pages > _displayPages && _displayPages > 1)
|
||||||
{
|
{
|
||||||
<li class="page-item@((_endPage < _pages) ? " app-pager-pointer" : " disabled")">
|
<li class="page-item@((_endPage < _pages) ? " app-pager-pointer" : " disabled")">
|
||||||
<a class="page-link" @onclick=@(async () => SkipPages("forward"))><span class="oi oi-media-skip-forward" title="skip forward" aria-hidden="true"></span></a>
|
<a class="page-link shadow-none" @onclick=@(async () => SkipPages("forward"))><span class="oi oi-media-skip-forward" title="skip forward" aria-hidden="true"></span></a>
|
||||||
</li>
|
</li>
|
||||||
}
|
}
|
||||||
<li class="page-item@((_page < _pages) ? " app-pager-pointer" : " disabled")">
|
<li class="page-item@((_page < _pages) ? " app-pager-pointer" : " disabled")">
|
||||||
<a class="page-link" @onclick=@(async () => UpdateList(_pages))><span class="oi oi-media-step-forward" title="end" aria-hidden="true"></span></a>
|
<a class="page-link shadow-none" @onclick=@(async () => UpdateList(_pages))><span class="oi oi-media-step-forward" title="end" aria-hidden="true"></span></a>
|
||||||
</li>
|
</li>
|
||||||
<li class="page-item disabled">
|
<li class="page-item disabled">
|
||||||
<a class="page-link" style="white-space: nowrap;">@Localizer["PageOfPages", _page, _pages]</a>
|
<a class="page-link shadow-none" style="white-space: nowrap;">@Localizer["PageOfPages", _page, _pages]</a>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
}
|
}
|
||||||
@ -250,16 +250,16 @@
|
|||||||
{
|
{
|
||||||
<ul class="pagination justify-content-center my-2">
|
<ul class="pagination justify-content-center my-2">
|
||||||
<li class="page-item@((_page > 1) ? " app-pager-pointer" : " disabled")">
|
<li class="page-item@((_page > 1) ? " app-pager-pointer" : " disabled")">
|
||||||
<a class="page-link" href="@PageUrl(1, _search)"><span class="oi oi-media-step-backward" title="start" aria-hidden="true"></span></a>
|
<a class="page-link shadow-none" href="@PageUrl(1, _search)"><span class="oi oi-media-step-backward" title="start" aria-hidden="true"></span></a>
|
||||||
</li>
|
</li>
|
||||||
@if (_pages > _displayPages && _displayPages > 1)
|
@if (_pages > _displayPages && _displayPages > 1)
|
||||||
{
|
{
|
||||||
<li class="page-item@((_page > _displayPages) ? " app-pager-pointer" : " disabled")">
|
<li class="page-item@((_page > _displayPages) ? " app-pager-pointer" : " disabled")">
|
||||||
<a class="page-link" href="@PageUrl(_startPage - 1, _search)"><span class="oi oi-media-skip-backward" title="skip back" aria-hidden="true"></span></a>
|
<a class="page-link shadow-none" href="@PageUrl(_startPage - 1, _search)"><span class="oi oi-media-skip-backward" title="skip back" aria-hidden="true"></span></a>
|
||||||
</li>
|
</li>
|
||||||
}
|
}
|
||||||
<li class="page-item@((_page > 1) ? " app-pager-pointer" : " disabled")">
|
<li class="page-item@((_page > 1) ? " app-pager-pointer" : " disabled")">
|
||||||
<a class="page-link" href="@PageUrl(((_page > 1) ? _page - 1 : _page), _search)"><span class="oi oi-chevron-left" title="previous" aria-hidden="true"></span></a>
|
<a class="page-link shadow-none" href="@PageUrl(((_page > 1) ? _page - 1 : _page), _search)"><span class="oi oi-chevron-left" title="previous" aria-hidden="true"></span></a>
|
||||||
</li>
|
</li>
|
||||||
@for (int i = _startPage; i <= _endPage; i++)
|
@for (int i = _startPage; i <= _endPage; i++)
|
||||||
{
|
{
|
||||||
@ -267,30 +267,30 @@
|
|||||||
if (pager == _page)
|
if (pager == _page)
|
||||||
{
|
{
|
||||||
<li class="page-item app-pager-pointer active">
|
<li class="page-item app-pager-pointer active">
|
||||||
<a class="page-link" href="@PageUrl(pager, _search)">@pager</a>
|
<a class="page-link shadow-none" href="@PageUrl(pager, _search)">@pager</a>
|
||||||
</li>
|
</li>
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
<li class="page-item app-pager-pointer">
|
<li class="page-item app-pager-pointer">
|
||||||
<a class="page-link" href="@PageUrl(pager, _search)">@pager</a>
|
<a class="page-link shadow-none" href="@PageUrl(pager, _search)">@pager</a>
|
||||||
</li>
|
</li>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
<li class="page-item@((_page < _pages) ? " app-pager-pointer" : " disabled")">
|
<li class="page-item@((_page < _pages) ? " app-pager-pointer" : " disabled")">
|
||||||
<a class="page-link" href="@PageUrl(((_page < _pages) ? _page + 1 : _page), _search)"><span class="oi oi-chevron-right" title="next" aria-hidden="true"></span></a>
|
<a class="page-link shadow-none" href="@PageUrl(((_page < _pages) ? _page + 1 : _page), _search)"><span class="oi oi-chevron-right" title="next" aria-hidden="true"></span></a>
|
||||||
</li>
|
</li>
|
||||||
@if (_pages > _displayPages && _displayPages > 1)
|
@if (_pages > _displayPages && _displayPages > 1)
|
||||||
{
|
{
|
||||||
<li class="page-item@((_endPage < _pages) ? " app-pager-pointer" : " disabled")">
|
<li class="page-item@((_endPage < _pages) ? " app-pager-pointer" : " disabled")">
|
||||||
<a class="page-link" href="@PageUrl(_endPage + 1, _search)"><span class="oi oi-media-skip-forward" title="skip forward" aria-hidden="true"></span></a>
|
<a class="page-link shadow-none" href="@PageUrl(_endPage + 1, _search)"><span class="oi oi-media-skip-forward" title="skip forward" aria-hidden="true"></span></a>
|
||||||
</li>
|
</li>
|
||||||
}
|
}
|
||||||
<li class="page-item@((_page < _pages) ? " app-pager-pointer" : " disabled")">
|
<li class="page-item@((_page < _pages) ? " app-pager-pointer" : " disabled")">
|
||||||
<a class="page-link" href="@PageUrl(_pages, _search)"><span class="oi oi-media-step-forward" title="end" aria-hidden="true"></span></a>
|
<a class="page-link shadow-none" href="@PageUrl(_pages, _search)"><span class="oi oi-media-step-forward" title="end" aria-hidden="true"></span></a>
|
||||||
</li>
|
</li>
|
||||||
<li class="page-item disabled">
|
<li class="page-item disabled">
|
||||||
<a class="page-link" style="white-space: nowrap;">@Localizer["PageOfPages", _page, _pages]</a>
|
<a class="page-link shadow-none" style="white-space: nowrap;">@Localizer["PageOfPages", _page, _pages]</a>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
}
|
}
|
||||||
@ -359,6 +359,9 @@
|
|||||||
[Parameter]
|
[Parameter]
|
||||||
public string SearchProperties { get; set; } // comma delimited list of property names to include in search
|
public string SearchProperties { get; set; } // comma delimited list of property names to include in search
|
||||||
|
|
||||||
|
[Parameter]
|
||||||
|
public string SearchBoxClass { get; set; } // class for Search box
|
||||||
|
|
||||||
[Parameter]
|
[Parameter]
|
||||||
public string Parameters { get; set; } // optional - querystring parameters in the form of "id=x&name=y" used in static render mode
|
public string Parameters { get; set; } // optional - querystring parameters in the form of "id=x&name=y" used in static render mode
|
||||||
|
|
||||||
|
@ -111,7 +111,7 @@
|
|||||||
[Parameter]
|
[Parameter]
|
||||||
public List<Permission> PermissionList { get; set; }
|
public List<Permission> PermissionList { get; set; }
|
||||||
|
|
||||||
protected override async Task OnInitializedAsync()
|
protected override async Task OnParametersSetAsync()
|
||||||
{
|
{
|
||||||
if (!string.IsNullOrEmpty(Permissions))
|
if (!string.IsNullOrEmpty(Permissions))
|
||||||
{
|
{
|
||||||
|
@ -4,11 +4,11 @@ using System.Threading.Tasks;
|
|||||||
|
|
||||||
namespace Oqtane.Modules.Controls
|
namespace Oqtane.Modules.Controls
|
||||||
{
|
{
|
||||||
public class RichTextEditorInterop
|
public class QuillEditorInterop
|
||||||
{
|
{
|
||||||
private readonly IJSRuntime _jsRuntime;
|
private readonly IJSRuntime _jsRuntime;
|
||||||
|
|
||||||
public RichTextEditorInterop(IJSRuntime jsRuntime)
|
public QuillEditorInterop(IJSRuntime jsRuntime)
|
||||||
{
|
{
|
||||||
_jsRuntime = jsRuntime;
|
_jsRuntime = jsRuntime;
|
||||||
}
|
}
|
||||||
@ -105,13 +105,25 @@ namespace Oqtane.Modules.Controls
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task InsertImage(ElementReference quillElement, string imageUrl, string altText)
|
public ValueTask<int> GetCurrentCursor(ElementReference quillElement)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return _jsRuntime.InvokeAsync<int>("Oqtane.RichTextEditor.getCurrentCursor", quillElement);
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
return new ValueTask<int>(Task.FromResult(0));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task InsertImage(ElementReference quillElement, string imageUrl, string altText, int editorIndex)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
_jsRuntime.InvokeAsync<object>(
|
_jsRuntime.InvokeAsync<object>(
|
||||||
"Oqtane.RichTextEditor.insertQuillImage",
|
"Oqtane.RichTextEditor.insertQuillImage",
|
||||||
quillElement, imageUrl, altText);
|
quillElement, imageUrl, altText, editorIndex);
|
||||||
return Task.CompletedTask;
|
return Task.CompletedTask;
|
||||||
}
|
}
|
||||||
catch
|
catch
|
578
Oqtane.Client/Modules/Controls/QuillJSTextEditor.razor
Normal file
578
Oqtane.Client/Modules/Controls/QuillJSTextEditor.razor
Normal file
@ -0,0 +1,578 @@
|
|||||||
|
@namespace Oqtane.Modules.Controls
|
||||||
|
@inherits ModuleControlBase
|
||||||
|
@implements ITextEditor
|
||||||
|
@inject ISettingService SettingService
|
||||||
|
@inject NavigationManager NavigationManager
|
||||||
|
@inject IStringLocalizer<QuillJSTextEditor> Localizer
|
||||||
|
@inject IStringLocalizer<SharedResources> SharedLocalizer
|
||||||
|
|
||||||
|
<div class="quill-text-editor">
|
||||||
|
<TabStrip ActiveTab="@_activetab">
|
||||||
|
@if (_allowRichText)
|
||||||
|
{
|
||||||
|
<TabPanel Name="Rich" Heading="Rich Text Editor" ResourceKey="RichTextEditor">
|
||||||
|
@if (_richfilemanager)
|
||||||
|
{
|
||||||
|
<FileManager @ref="_fileManager" Filter="@PageState.Site.ImageFiles" />
|
||||||
|
<ModuleMessage Message="@_message" Type="MessageType.Warning"></ModuleMessage>
|
||||||
|
<br />
|
||||||
|
}
|
||||||
|
<div class="d-flex justify-content-center mb-2">
|
||||||
|
@if (_allowFileManagement)
|
||||||
|
{
|
||||||
|
<button type="button" class="btn btn-primary" @onclick="InsertRichImage">@Localizer["InsertImage"]</button>
|
||||||
|
}
|
||||||
|
@if (_richfilemanager)
|
||||||
|
{
|
||||||
|
@((MarkupString)" ")
|
||||||
|
<button type="button" class="btn btn-secondary" @onclick="CloseRichFileManager">@Localizer["Close"]</button>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col">
|
||||||
|
<div @ref="@_toolBar">
|
||||||
|
@if (!string.IsNullOrEmpty(_toolbarContent))
|
||||||
|
{
|
||||||
|
@((MarkupString)_toolbarContent)
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
<select class="ql-header">
|
||||||
|
<option selected=""></option>
|
||||||
|
<option value="1"></option>
|
||||||
|
<option value="2"></option>
|
||||||
|
<option value="3"></option>
|
||||||
|
<option value="4"></option>
|
||||||
|
<option value="5"></option>
|
||||||
|
</select>
|
||||||
|
<span class="ql-formats">
|
||||||
|
<button class="ql-bold"></button>
|
||||||
|
<button class="ql-italic"></button>
|
||||||
|
<button class="ql-underline"></button>
|
||||||
|
<button class="ql-strike"></button>
|
||||||
|
</span>
|
||||||
|
<span class="ql-formats">
|
||||||
|
<select class="ql-color"></select>
|
||||||
|
<select class="ql-background"></select>
|
||||||
|
</span>
|
||||||
|
<span class="ql-formats">
|
||||||
|
<button class="ql-list" value="ordered"></button>
|
||||||
|
<button class="ql-list" value="bullet"></button>
|
||||||
|
</span>
|
||||||
|
<span class="ql-formats">
|
||||||
|
<button class="ql-link"></button>
|
||||||
|
</span>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
<div @ref="@_editorElement"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</TabPanel>
|
||||||
|
}
|
||||||
|
@if (_allowRawHtml)
|
||||||
|
{
|
||||||
|
<TabPanel Name="Raw" Heading="Raw HTML Editor" ResourceKey="HtmlEditor">
|
||||||
|
@if (_rawfilemanager)
|
||||||
|
{
|
||||||
|
<FileManager @ref="_fileManager" Filter="@PageState.Site.ImageFiles" />
|
||||||
|
<ModuleMessage Message="@_message" Type="MessageType.Warning"></ModuleMessage>
|
||||||
|
<br />
|
||||||
|
}
|
||||||
|
<div class="d-flex justify-content-center mb-2">
|
||||||
|
@if (_allowFileManagement)
|
||||||
|
{
|
||||||
|
<button type="button" class="btn btn-primary" @onclick="InsertRawImage">@Localizer["InsertImage"]</button>
|
||||||
|
}
|
||||||
|
@if (_rawfilemanager)
|
||||||
|
{
|
||||||
|
@((MarkupString)" ")
|
||||||
|
<button type="button" class="btn btn-secondary" @onclick="CloseRawFileManager">@Localizer["Close"]</button>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
@if (ReadOnly)
|
||||||
|
{
|
||||||
|
<textarea id="@_rawhtmlid" class="form-control" placeholder="@Placeholder" @bind="@_rawhtml" rows="10" readonly></textarea>
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
<textarea id="@_rawhtmlid" class="form-control" placeholder="@Placeholder" @bind="@_rawhtml" rows="10"></textarea>
|
||||||
|
}
|
||||||
|
</TabPanel>
|
||||||
|
}
|
||||||
|
@if (_allowSettings)
|
||||||
|
{
|
||||||
|
<TabPanel Name="Settings" Heading="Settings" ResourceKey="Settings">
|
||||||
|
<div class="quill-text-editor-settings">
|
||||||
|
<div class="row mb-1 align-items-center">
|
||||||
|
<Label Class="col-sm-3" For="Scope" ResourceKey="Scope" ResourceType="@resourceType" HelpText="Specify if settings are scoped to the module or site">Scope: </Label>
|
||||||
|
<div class="col-sm-9">
|
||||||
|
<select id="Scope" class="form-select" value="@_scopeSetting" @onchange="(e => ScopeChanged(e))">
|
||||||
|
<option value="Module">@SharedLocalizer["Module"]</option>
|
||||||
|
@if (UserSecurity.IsAuthorized(PageState.User, RoleNames.Admin))
|
||||||
|
{
|
||||||
|
<option value="Site">@SharedLocalizer["Site"]</option>
|
||||||
|
}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row mb-1 align-items-center">
|
||||||
|
<Label Class="col-sm-3" For="AllowRichText" ResourceKey="AllowRichText" ResourceType="@resourceType" HelpText="Specify if editors can use the Rich Text Editor">Rich Text Editor? </Label>
|
||||||
|
<div class="col-sm-9">
|
||||||
|
<select id="AllowRichText" class="form-select" @bind="@_allowRichTextSetting" required>
|
||||||
|
<option value="True">@SharedLocalizer["Yes"]</option>
|
||||||
|
<option value="False">@SharedLocalizer["No"]</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row mb-1 align-items-center">
|
||||||
|
<Label Class="col-sm-3" For="AllowRawHtml" ResourceKey="AllowRawHtml" ResourceType="@resourceType" HelpText="Specify if editors can use the Raw HTML Editor">Raw HTML Editor? </Label>
|
||||||
|
<div class="col-sm-9">
|
||||||
|
<select id="AllowRawHtml" class="form-select" @bind="@_allowRawHtmlSetting" required>
|
||||||
|
<option value="True">@SharedLocalizer["Yes"]</option>
|
||||||
|
<option value="False">@SharedLocalizer["No"]</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row mb-1 align-items-center">
|
||||||
|
<Label Class="col-sm-3" For="AllowFileManagement" ResourceKey="AllowFileManagement" ResourceType="@resourceType" HelpText="Specify if editors can upload and insert images">Insert Images? </Label>
|
||||||
|
<div class="col-sm-9">
|
||||||
|
<select id="AllowFileManagement" class="form-select" @bind="@_allowFileManagementSetting" required>
|
||||||
|
<option value="True">@SharedLocalizer["Yes"]</option>
|
||||||
|
<option value="False">@SharedLocalizer["No"]</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row mb-1 align-items-center">
|
||||||
|
<Label Class="col-sm-3" For="Theme" ResourceKey="Theme" ResourceType="@resourceType" HelpText="Specify the Rich Text Editor's theme">Theme: </Label>
|
||||||
|
<div class="col-sm-9">
|
||||||
|
<input type="text" id="Theme" class="form-control" @bind="_themeSetting" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row mb-1 align-items-center">
|
||||||
|
<Label Class="col-sm-3" For="DebugLevel" ResourceKey="DebugLevel" ResourceType="@resourceType" HelpText="Specify the Debug Level">Debug Level: </Label>
|
||||||
|
<div class="col-sm-9">
|
||||||
|
<select id="DebugLevel" class="form-select" @bind="_debugLevelSetting">
|
||||||
|
@foreach (var level in _debugLevels)
|
||||||
|
{
|
||||||
|
<option value="@level">@level</option>
|
||||||
|
}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row mb-1 align-items-center">
|
||||||
|
<Label Class="col-sm-3" For="ToolbarContent" ResourceKey="ToolbarContent" ResourceType="@resourceType" HelpText="Specify any toolbar content to customize the Rich Text Editor">Toolbar Content: </Label>
|
||||||
|
<div class="col-sm-9">
|
||||||
|
<textarea id="ToolbarContent" class="form-control" @bind="_toolbarContentSetting" rows="3" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row mb-1 align-items-center">
|
||||||
|
<div class="col-sm-9 offset-sm-3">
|
||||||
|
<button type="button" class="btn btn-success" @onclick="@(async () => await UpdateSettings())">@Localizer["SaveSettings"]</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</TabPanel>
|
||||||
|
}
|
||||||
|
</TabStrip>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
@code {
|
||||||
|
public string Name => "QuillJS";
|
||||||
|
|
||||||
|
private string resourceType = "Oqtane.Modules.Controls.QuillJSTextEditor, Oqtane.Client";
|
||||||
|
|
||||||
|
private bool _settingsLoaded;
|
||||||
|
private bool _initialized = false;
|
||||||
|
|
||||||
|
private QuillEditorInterop _interop;
|
||||||
|
private FileManager _fileManager;
|
||||||
|
private string _activetab = "Rich";
|
||||||
|
private bool _allowSettings = false;
|
||||||
|
|
||||||
|
private bool _allowFileManagement = false;
|
||||||
|
private bool _allowRawHtml = false;
|
||||||
|
private bool _allowRichText = false;
|
||||||
|
private string _theme = "snow";
|
||||||
|
private string _debugLevel = "info";
|
||||||
|
private string _toolbarContent = string.Empty;
|
||||||
|
|
||||||
|
private string _scopeSetting = "Module";
|
||||||
|
private string _allowFileManagementSetting = "False";
|
||||||
|
private string _allowRawHtmlSetting = "False";
|
||||||
|
private string _allowRichTextSetting = "False";
|
||||||
|
private string _themeSetting = "snow";
|
||||||
|
private string _debugLevelSetting = "info";
|
||||||
|
private string _toolbarContentSetting = string.Empty;
|
||||||
|
|
||||||
|
private ElementReference _editorElement;
|
||||||
|
private ElementReference _toolBar;
|
||||||
|
private bool _richfilemanager = false;
|
||||||
|
private string _richhtml = string.Empty;
|
||||||
|
private string _originalrichhtml = string.Empty;
|
||||||
|
|
||||||
|
private bool _rawfilemanager = false;
|
||||||
|
private string _rawhtmlid = "RawHtmlEditor_" + Guid.NewGuid().ToString("N");
|
||||||
|
private string _rawhtml = string.Empty;
|
||||||
|
private string _originalrawhtml = string.Empty;
|
||||||
|
|
||||||
|
private string _message = string.Empty;
|
||||||
|
private bool _contentchanged = false;
|
||||||
|
private int _editorIndex;
|
||||||
|
|
||||||
|
private List<string> _debugLevels = new List<string> { "info", "log", "warn", "error" };
|
||||||
|
|
||||||
|
[Parameter]
|
||||||
|
public bool ReadOnly { get; set; }
|
||||||
|
|
||||||
|
[Parameter]
|
||||||
|
public string Placeholder { get; set; }
|
||||||
|
|
||||||
|
// the following parameters were supported by the original RichTextEditor and can be passed as optional static parameters
|
||||||
|
|
||||||
|
[Parameter]
|
||||||
|
public bool? AllowFileManagement { get; set; }
|
||||||
|
|
||||||
|
[Parameter]
|
||||||
|
public bool? AllowRichText { get; set; }
|
||||||
|
|
||||||
|
[Parameter]
|
||||||
|
public bool? AllowRawHtml { get; set; }
|
||||||
|
|
||||||
|
[Parameter]
|
||||||
|
public string Theme { get; set; }
|
||||||
|
|
||||||
|
[Parameter]
|
||||||
|
public string DebugLevel { get; set; }
|
||||||
|
|
||||||
|
public override List<Resource> Resources { get; set; } = new List<Resource>()
|
||||||
|
{
|
||||||
|
new Resource { ResourceType = ResourceType.Script, Bundle = "Quill", Url = "js/quill.min.js", Location = ResourceLocation.Body },
|
||||||
|
new Resource { ResourceType = ResourceType.Script, Bundle = "Quill", Url = "js/quill-blot-formatter.min.js", Location = ResourceLocation.Body },
|
||||||
|
new Resource { ResourceType = ResourceType.Script, Bundle = "Quill", Url = "js/quill-interop.js", Location = ResourceLocation.Body }
|
||||||
|
};
|
||||||
|
|
||||||
|
protected override void OnInitialized()
|
||||||
|
{
|
||||||
|
_interop = new QuillEditorInterop(JSRuntime);
|
||||||
|
|
||||||
|
if (string.IsNullOrEmpty(Placeholder))
|
||||||
|
{
|
||||||
|
Placeholder = Localizer["Placeholder"];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnParametersSet()
|
||||||
|
{
|
||||||
|
LoadSettings();
|
||||||
|
|
||||||
|
if (!_allowRichText)
|
||||||
|
{
|
||||||
|
_activetab = "Raw";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override async Task OnAfterRenderAsync(bool firstRender)
|
||||||
|
{
|
||||||
|
if (firstRender)
|
||||||
|
{
|
||||||
|
// include CSS theme
|
||||||
|
var interop = new Interop(JSRuntime);
|
||||||
|
await interop.IncludeLink("", "stylesheet", $"css/quill/quill.{_theme}.css", "text/css", "", "", "");
|
||||||
|
}
|
||||||
|
|
||||||
|
await base.OnAfterRenderAsync(firstRender);
|
||||||
|
|
||||||
|
if (_allowRichText)
|
||||||
|
{
|
||||||
|
if (firstRender)
|
||||||
|
{
|
||||||
|
await _interop.CreateEditor(
|
||||||
|
_editorElement,
|
||||||
|
_toolBar,
|
||||||
|
ReadOnly,
|
||||||
|
Placeholder,
|
||||||
|
_theme,
|
||||||
|
_debugLevel);
|
||||||
|
|
||||||
|
await _interop.LoadEditorContent(_editorElement, _richhtml);
|
||||||
|
|
||||||
|
// preserve a copy of the content (Quill sanitizes content so we need to retrieve it from the editor as it may have been modified)
|
||||||
|
_originalrichhtml = await _interop.GetHtml(_editorElement);
|
||||||
|
|
||||||
|
_initialized = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (_initialized)
|
||||||
|
{
|
||||||
|
if (_contentchanged)
|
||||||
|
{
|
||||||
|
// reload editor if Content passed to component has changed
|
||||||
|
await _interop.LoadEditorContent(_editorElement, _richhtml);
|
||||||
|
_originalrichhtml = await _interop.GetHtml(_editorElement);
|
||||||
|
|
||||||
|
_contentchanged = false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// preserve changed content on re-render event
|
||||||
|
var richhtml = await _interop.GetHtml(_editorElement);
|
||||||
|
if (richhtml != _richhtml)
|
||||||
|
{
|
||||||
|
_richhtml = richhtml;
|
||||||
|
await _interop.LoadEditorContent(_editorElement, _richhtml);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Initialize(string content)
|
||||||
|
{
|
||||||
|
_richhtml = content;
|
||||||
|
_rawhtml = content;
|
||||||
|
_originalrichhtml = "";
|
||||||
|
_richhtml = content;
|
||||||
|
if (!_contentchanged)
|
||||||
|
{
|
||||||
|
_contentchanged = content != _originalrawhtml;
|
||||||
|
}
|
||||||
|
|
||||||
|
_originalrawhtml = _rawhtml; // preserve for comparison later
|
||||||
|
|
||||||
|
StateHasChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<string> GetContent()
|
||||||
|
{
|
||||||
|
// evaluate raw html content as first priority
|
||||||
|
if (_rawhtml != _originalrawhtml)
|
||||||
|
{
|
||||||
|
return _rawhtml;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var richhtml = "";
|
||||||
|
|
||||||
|
if (_allowRichText)
|
||||||
|
{
|
||||||
|
richhtml = await _interop.GetHtml(_editorElement);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (richhtml != _originalrichhtml && !string.IsNullOrEmpty(richhtml))
|
||||||
|
{
|
||||||
|
// convert Quill's empty content to empty string
|
||||||
|
if (richhtml == "<p><br></p>")
|
||||||
|
{
|
||||||
|
richhtml = string.Empty;
|
||||||
|
}
|
||||||
|
return richhtml;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// return original raw html content
|
||||||
|
return _originalrawhtml;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void CloseRichFileManager()
|
||||||
|
{
|
||||||
|
_richfilemanager = false;
|
||||||
|
_message = string.Empty;
|
||||||
|
StateHasChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void CloseRawFileManager()
|
||||||
|
{
|
||||||
|
_rawfilemanager = false;
|
||||||
|
_message = string.Empty;
|
||||||
|
StateHasChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<string> GetHtml()
|
||||||
|
{
|
||||||
|
// evaluate raw html content as first priority
|
||||||
|
if (_rawhtml != _originalrawhtml)
|
||||||
|
{
|
||||||
|
return _rawhtml;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var richhtml = "";
|
||||||
|
|
||||||
|
if (_allowRichText)
|
||||||
|
{
|
||||||
|
richhtml = await _interop.GetHtml(_editorElement);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (richhtml != _originalrichhtml && !string.IsNullOrEmpty(richhtml))
|
||||||
|
{
|
||||||
|
// convert Quill's empty content to empty string
|
||||||
|
if (richhtml == "<p><br></p>")
|
||||||
|
{
|
||||||
|
richhtml = string.Empty;
|
||||||
|
}
|
||||||
|
return richhtml;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// return original raw html content
|
||||||
|
return _originalrawhtml;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task InsertRichImage()
|
||||||
|
{
|
||||||
|
_message = string.Empty;
|
||||||
|
if (_richfilemanager)
|
||||||
|
{
|
||||||
|
var file = _fileManager.GetFile();
|
||||||
|
if (file != null)
|
||||||
|
{
|
||||||
|
await _interop.InsertImage(_editorElement, file.Url, ((!string.IsNullOrEmpty(file.Description)) ? file.Description : file.Name), _editorIndex);
|
||||||
|
_richhtml = await _interop.GetHtml(_editorElement);
|
||||||
|
_richfilemanager = false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_message = Localizer["Message.Require.Image"];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_editorIndex = await _interop.GetCurrentCursor(_editorElement);
|
||||||
|
_richfilemanager = true;
|
||||||
|
}
|
||||||
|
StateHasChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task InsertRawImage()
|
||||||
|
{
|
||||||
|
_message = string.Empty;
|
||||||
|
if (_rawfilemanager)
|
||||||
|
{
|
||||||
|
var file = _fileManager.GetFile();
|
||||||
|
if (file != null)
|
||||||
|
{
|
||||||
|
var interop = new Interop(JSRuntime);
|
||||||
|
int pos = await interop.GetCaretPosition(_rawhtmlid);
|
||||||
|
var image = "<img src=\"" + file.Url + "\" alt=\"" + ((!string.IsNullOrEmpty(file.Description)) ? file.Description : file.Name) + "\" class=\"img-fluid\">";
|
||||||
|
_rawhtml = _rawhtml.Substring(0, pos) + image + _rawhtml.Substring(pos);
|
||||||
|
_rawfilemanager = false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_message = Localizer["Message.Require.Image"];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_rawfilemanager = true;
|
||||||
|
}
|
||||||
|
StateHasChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ScopeChanged(ChangeEventArgs e)
|
||||||
|
{
|
||||||
|
_scopeSetting = (string)e.Value;
|
||||||
|
LoadSettings();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void LoadSettings(bool reload = false)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (!_settingsLoaded || reload)
|
||||||
|
{
|
||||||
|
_allowFileManagement = bool.Parse(GetSetting("Component", "QuillTextEditor_AllowFileManagement", "True"));
|
||||||
|
_allowRawHtml = bool.Parse(GetSetting("Component", "QuillTextEditor_AllowRawHtml", "True"));
|
||||||
|
_allowRichText = bool.Parse(GetSetting("Component", "QuillTextEditor_AllowRichText", "True"));
|
||||||
|
_theme = GetSetting("Component", "QuillTextEditor_Theme", "snow");
|
||||||
|
_debugLevel = GetSetting("Component", "QuillTextEditor_DebugLevel", "info");
|
||||||
|
_toolbarContent = GetSetting("Component", "QuillTextEditor_ToolbarContent", string.Empty);
|
||||||
|
|
||||||
|
// optional static parameter overrides
|
||||||
|
if (AllowFileManagement != null) _allowFileManagement = AllowFileManagement.Value;
|
||||||
|
if (AllowRichText != null) _allowRichText = AllowRichText.Value;
|
||||||
|
if (AllowRawHtml != null) _allowRawHtml = AllowRawHtml.Value;
|
||||||
|
if (!string.IsNullOrEmpty(Theme)) _theme = Theme;
|
||||||
|
if (!string.IsNullOrEmpty(DebugLevel)) _debugLevel = DebugLevel;
|
||||||
|
}
|
||||||
|
|
||||||
|
_allowSettings = PageState.EditMode && UserSecurity.IsAuthorized(PageState.User, PermissionNames.Edit, PageState.Page.PermissionList);
|
||||||
|
if (_allowSettings)
|
||||||
|
{
|
||||||
|
_allowFileManagementSetting = GetSetting(_scopeSetting, "QuillTextEditor_AllowFileManagement", "True");
|
||||||
|
_allowRawHtmlSetting = GetSetting(_scopeSetting, "QuillTextEditor_AllowRawHtml", "True");
|
||||||
|
_allowRichTextSetting = GetSetting(_scopeSetting, "QuillTextEditor_AllowRichText", "True");
|
||||||
|
_themeSetting = GetSetting(_scopeSetting, "QuillTextEditor_Theme", "snow");
|
||||||
|
_debugLevelSetting = GetSetting(_scopeSetting, "QuillTextEditor_DebugLevel", "info");
|
||||||
|
_toolbarContentSetting = GetSetting(_scopeSetting, "QuillTextEditor_ToolbarContent", string.Empty);
|
||||||
|
}
|
||||||
|
|
||||||
|
_settingsLoaded = true;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
AddModuleMessage(ex.Message, MessageType.Error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private string GetSetting(string scope, string settingName, string defaultValue)
|
||||||
|
{
|
||||||
|
var settingValue = "";
|
||||||
|
switch (scope)
|
||||||
|
{
|
||||||
|
case "Component":
|
||||||
|
settingValue = SettingService.GetSetting(PageState.Site.Settings, settingName, defaultValue);
|
||||||
|
settingValue = SettingService.GetSetting(ModuleState.Settings, settingName, settingValue);
|
||||||
|
break;
|
||||||
|
case "Site":
|
||||||
|
settingValue = SettingService.GetSetting(PageState.Site.Settings, settingName, defaultValue);
|
||||||
|
break;
|
||||||
|
case "Module":
|
||||||
|
settingValue = SettingService.GetSetting(ModuleState.Settings, settingName, defaultValue);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return settingValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task UpdateSettings()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (_scopeSetting == "Site" && UserSecurity.IsAuthorized(PageState.User, RoleNames.Admin))
|
||||||
|
{
|
||||||
|
var settings = await SettingService.GetSiteSettingsAsync(PageState.Site.SiteId);
|
||||||
|
settings = SettingService.SetSetting(settings, "QuillTextEditor_AllowFileManagement", _allowFileManagementSetting);
|
||||||
|
settings = SettingService.SetSetting(settings, "QuillTextEditor_AllowRawHtml", _allowRawHtmlSetting);
|
||||||
|
settings = SettingService.SetSetting(settings, "QuillTextEditor_AllowRichText", _allowRichTextSetting);
|
||||||
|
settings = SettingService.SetSetting(settings, "QuillTextEditor_Theme", _themeSetting);
|
||||||
|
settings = SettingService.SetSetting(settings, "QuillTextEditor_DebugLevel", _debugLevelSetting);
|
||||||
|
settings = SettingService.SetSetting(settings, "QuillTextEditor_ToolbarContent", _toolbarContentSetting);
|
||||||
|
await SettingService.UpdateSiteSettingsAsync(settings, PageState.Site.SiteId);
|
||||||
|
}
|
||||||
|
else if (_scopeSetting == "Module")
|
||||||
|
{
|
||||||
|
var settings = await SettingService.GetModuleSettingsAsync(ModuleState.ModuleId);
|
||||||
|
settings = SettingService.SetSetting(settings, "QuillTextEditor_AllowFileManagement", _allowFileManagementSetting);
|
||||||
|
settings = SettingService.SetSetting(settings, "QuillTextEditor_AllowRawHtml", _allowRawHtmlSetting);
|
||||||
|
settings = SettingService.SetSetting(settings, "QuillTextEditor_AllowRichText", _allowRichTextSetting);
|
||||||
|
settings = SettingService.SetSetting(settings, "QuillTextEditor_Theme", _themeSetting);
|
||||||
|
settings = SettingService.SetSetting(settings, "QuillTextEditor_DebugLevel", _debugLevelSetting);
|
||||||
|
settings = SettingService.SetSetting(settings, "QuillTextEditor_ToolbarContent", _toolbarContentSetting);
|
||||||
|
await SettingService.UpdateModuleSettingsAsync(settings,ModuleState.ModuleId);
|
||||||
|
}
|
||||||
|
LoadSettings(true);
|
||||||
|
|
||||||
|
NavigationManager.NavigateTo(NavigationManager.Uri, true);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
AddModuleMessage(ex.Message, MessageType.Error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,127 +1,22 @@
|
|||||||
@using System.Text.RegularExpressions
|
@using System.Text.RegularExpressions
|
||||||
|
@using Microsoft.AspNetCore.Components.Rendering
|
||||||
|
@using Microsoft.Extensions.DependencyInjection
|
||||||
@namespace Oqtane.Modules.Controls
|
@namespace Oqtane.Modules.Controls
|
||||||
@inherits ModuleControlBase
|
@inherits ModuleControlBase
|
||||||
|
@inject IServiceProvider ServiceProvider
|
||||||
@inject ISettingService SettingService
|
@inject ISettingService SettingService
|
||||||
@inject IStringLocalizer<RichTextEditor> Localizer
|
@inject IStringLocalizer<RichTextEditor> Localizer
|
||||||
|
|
||||||
<div class="row" style="margin-bottom: 50px;">
|
<div class="row" style="margin-bottom: 50px;">
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<TabStrip ActiveTab="@_activetab">
|
@_textEditorComponent
|
||||||
@if (AllowRichText)
|
|
||||||
{
|
|
||||||
<TabPanel Name="Rich" Heading="Rich Text Editor" ResourceKey="RichTextEditor">
|
|
||||||
@if (_richfilemanager)
|
|
||||||
{
|
|
||||||
<FileManager @ref="_fileManager" Filter="@PageState.Site.ImageFiles" />
|
|
||||||
<ModuleMessage Message="@_message" Type="MessageType.Warning"></ModuleMessage>
|
|
||||||
<br />
|
|
||||||
}
|
|
||||||
<div class="d-flex justify-content-center mb-2">
|
|
||||||
@if (AllowFileManagement)
|
|
||||||
{
|
|
||||||
<button type="button" class="btn btn-primary" @onclick="InsertRichImage">@Localizer["InsertImage"]</button>
|
|
||||||
}
|
|
||||||
@if (_richfilemanager)
|
|
||||||
{
|
|
||||||
@((MarkupString)" ")
|
|
||||||
<button type="button" class="btn btn-secondary" @onclick="CloseRichFileManager">@Localizer["Close"]</button>
|
|
||||||
}
|
|
||||||
</div>
|
|
||||||
<div class="row">
|
|
||||||
<div class="col">
|
|
||||||
<div @ref="@_toolBar">
|
|
||||||
@if (ToolbarContent != null)
|
|
||||||
{
|
|
||||||
@ToolbarContent
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
<select class="ql-header">
|
|
||||||
<option selected=""></option>
|
|
||||||
<option value="1"></option>
|
|
||||||
<option value="2"></option>
|
|
||||||
<option value="3"></option>
|
|
||||||
<option value="4"></option>
|
|
||||||
<option value="5"></option>
|
|
||||||
</select>
|
|
||||||
<span class="ql-formats">
|
|
||||||
<button class="ql-bold"></button>
|
|
||||||
<button class="ql-italic"></button>
|
|
||||||
<button class="ql-underline"></button>
|
|
||||||
<button class="ql-strike"></button>
|
|
||||||
</span>
|
|
||||||
<span class="ql-formats">
|
|
||||||
<select class="ql-color"></select>
|
|
||||||
<select class="ql-background"></select>
|
|
||||||
</span>
|
|
||||||
<span class="ql-formats">
|
|
||||||
<button class="ql-list" value="ordered"></button>
|
|
||||||
<button class="ql-list" value="bullet"></button>
|
|
||||||
</span>
|
|
||||||
<span class="ql-formats">
|
|
||||||
<button class="ql-link"></button>
|
|
||||||
</span>
|
|
||||||
}
|
|
||||||
</div>
|
|
||||||
<div @ref="@_editorElement"></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</TabPanel>
|
|
||||||
}
|
|
||||||
@if (AllowRawHtml)
|
|
||||||
{
|
|
||||||
<TabPanel Name="Raw" Heading="Raw HTML Editor" ResourceKey="HtmlEditor">
|
|
||||||
@if (_rawfilemanager)
|
|
||||||
{
|
|
||||||
<FileManager @ref="_fileManager" Filter="@PageState.Site.ImageFiles" />
|
|
||||||
<ModuleMessage Message="@_message" Type="MessageType.Warning"></ModuleMessage>
|
|
||||||
<br />
|
|
||||||
}
|
|
||||||
<div class="d-flex justify-content-center mb-2">
|
|
||||||
@if (AllowFileManagement)
|
|
||||||
{
|
|
||||||
<button type="button" class="btn btn-primary" @onclick="InsertRawImage">@Localizer["InsertImage"]</button>
|
|
||||||
}
|
|
||||||
@if (_rawfilemanager)
|
|
||||||
{
|
|
||||||
@((MarkupString)" ")
|
|
||||||
<button type="button" class="btn btn-secondary" @onclick="CloseRawFileManager">@Localizer["Close"]</button>
|
|
||||||
}
|
|
||||||
</div>
|
|
||||||
@if (ReadOnly)
|
|
||||||
{
|
|
||||||
<textarea id="@_rawhtmlid" class="form-control" placeholder="@Placeholder" @bind="@_rawhtml" rows="10" readonly></textarea>
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
<textarea id="@_rawhtmlid" class="form-control" placeholder="@Placeholder" @bind="@_rawhtml" rows="10"></textarea>
|
|
||||||
}
|
|
||||||
</TabPanel>
|
|
||||||
}
|
|
||||||
</TabStrip>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@code {
|
@code {
|
||||||
private bool _initialized = false;
|
private string _textEditorType;
|
||||||
|
private RenderFragment _textEditorComponent;
|
||||||
private RichTextEditorInterop interop;
|
private ITextEditor _textEditor;
|
||||||
private FileManager _fileManager;
|
|
||||||
private string _activetab = "Rich";
|
|
||||||
|
|
||||||
private ElementReference _editorElement;
|
|
||||||
private ElementReference _toolBar;
|
|
||||||
private bool _richfilemanager = false;
|
|
||||||
private string _richhtml = string.Empty;
|
|
||||||
private string _originalrichhtml = string.Empty;
|
|
||||||
|
|
||||||
private bool _rawfilemanager = false;
|
|
||||||
private string _rawhtmlid = "RawHtmlEditor_" + Guid.NewGuid().ToString("N");
|
|
||||||
private string _rawhtml = string.Empty;
|
|
||||||
private string _originalrawhtml = string.Empty;
|
|
||||||
|
|
||||||
private string _message = string.Empty;
|
|
||||||
private bool _contentchanged = false;
|
|
||||||
|
|
||||||
[Parameter]
|
[Parameter]
|
||||||
public string Content { get; set; }
|
public string Content { get; set; }
|
||||||
@ -133,198 +28,100 @@
|
|||||||
public string Placeholder { get; set; }
|
public string Placeholder { get; set; }
|
||||||
|
|
||||||
[Parameter]
|
[Parameter]
|
||||||
public bool AllowFileManagement { get; set; } = true;
|
public string Provider { get; set; }
|
||||||
|
|
||||||
[Parameter]
|
[Parameter(CaptureUnmatchedValues = true)]
|
||||||
public bool AllowRichText { get; set; } = true;
|
public Dictionary<string, object> AdditionalAttributes { get; set; } = new Dictionary<string, object>();
|
||||||
|
|
||||||
[Parameter]
|
|
||||||
public bool AllowRawHtml { get; set; } = true;
|
|
||||||
|
|
||||||
// parameters only applicable to rich text editor
|
|
||||||
[Parameter]
|
|
||||||
public RenderFragment ToolbarContent { get; set; }
|
|
||||||
|
|
||||||
[Parameter]
|
|
||||||
public string Theme { get; set; } = "snow";
|
|
||||||
|
|
||||||
[Parameter]
|
|
||||||
public string DebugLevel { get; set; } = "info";
|
|
||||||
|
|
||||||
public override List<Resource> Resources => new List<Resource>()
|
|
||||||
{
|
|
||||||
new Resource { ResourceType = ResourceType.Script, Bundle = "Quill", Url = "js/quill.min.js", Location = ResourceLocation.Body },
|
|
||||||
new Resource { ResourceType = ResourceType.Script, Bundle = "Quill", Url = "js/quill-blot-formatter.min.js", Location = ResourceLocation.Body },
|
|
||||||
new Resource { ResourceType = ResourceType.Script, Bundle = "Quill", Url = "js/quill-interop.js", Location = ResourceLocation.Body }
|
|
||||||
};
|
|
||||||
|
|
||||||
protected override void OnInitialized()
|
protected override void OnInitialized()
|
||||||
{
|
{
|
||||||
interop = new RichTextEditorInterop(JSRuntime);
|
_textEditorType = GetTextEditorType();
|
||||||
if (string.IsNullOrEmpty(Placeholder))
|
|
||||||
{
|
|
||||||
Placeholder = Localizer["Placeholder"];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnParametersSet()
|
protected override void OnParametersSet()
|
||||||
{
|
{
|
||||||
_richhtml = Content;
|
_textEditorComponent = (builder) =>
|
||||||
_rawhtml = Content;
|
|
||||||
_originalrawhtml = _rawhtml; // preserve for comparison later
|
|
||||||
_originalrichhtml = "";
|
|
||||||
_contentchanged = true; // identifies when Content parameter has changed
|
|
||||||
|
|
||||||
if (!AllowRichText)
|
|
||||||
{
|
{
|
||||||
_activetab = "Raw";
|
CreateTextEditor(builder);
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override async Task OnAfterRenderAsync(bool firstRender)
|
protected override async Task OnAfterRenderAsync(bool firstRender)
|
||||||
{
|
{
|
||||||
|
if(_textEditor != null)
|
||||||
|
{
|
||||||
|
_textEditor.Initialize(Content);
|
||||||
|
}
|
||||||
|
|
||||||
await base.OnAfterRenderAsync(firstRender);
|
await base.OnAfterRenderAsync(firstRender);
|
||||||
|
|
||||||
if (AllowRichText)
|
|
||||||
{
|
|
||||||
if (firstRender)
|
|
||||||
{
|
|
||||||
await interop.CreateEditor(
|
|
||||||
_editorElement,
|
|
||||||
_toolBar,
|
|
||||||
ReadOnly,
|
|
||||||
Placeholder,
|
|
||||||
Theme,
|
|
||||||
DebugLevel);
|
|
||||||
|
|
||||||
await interop.LoadEditorContent(_editorElement, _richhtml);
|
|
||||||
|
|
||||||
// preserve a copy of the content (Quill sanitizes content so we need to retrieve it from the editor as it may have been modified)
|
|
||||||
_originalrichhtml = await interop.GetHtml(_editorElement);
|
|
||||||
|
|
||||||
_initialized = true;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (_initialized)
|
|
||||||
{
|
|
||||||
if (_contentchanged)
|
|
||||||
{
|
|
||||||
// reload editor if Content passed to component has changed
|
|
||||||
await interop.LoadEditorContent(_editorElement, _richhtml);
|
|
||||||
_originalrichhtml = await interop.GetHtml(_editorElement);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// preserve changed content on re-render event
|
|
||||||
var richhtml = await interop.GetHtml(_editorElement);
|
|
||||||
if (richhtml != _richhtml)
|
|
||||||
{
|
|
||||||
_richhtml = richhtml;
|
|
||||||
await interop.LoadEditorContent(_editorElement, _richhtml);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
_contentchanged = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void CloseRichFileManager()
|
|
||||||
{
|
|
||||||
_richfilemanager = false;
|
|
||||||
_message = string.Empty;
|
|
||||||
StateHasChanged();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void CloseRawFileManager()
|
|
||||||
{
|
|
||||||
_rawfilemanager = false;
|
|
||||||
_message = string.Empty;
|
|
||||||
StateHasChanged();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<string> GetHtml()
|
public async Task<string> GetHtml()
|
||||||
{
|
{
|
||||||
// evaluate raw html content as first priority
|
return await _textEditor.GetContent();
|
||||||
if (_rawhtml != _originalrawhtml)
|
}
|
||||||
|
|
||||||
|
private void CreateTextEditor(RenderTreeBuilder builder)
|
||||||
{
|
{
|
||||||
return _rawhtml;
|
if(!string.IsNullOrEmpty(_textEditorType))
|
||||||
|
{
|
||||||
|
var editorType = Type.GetType(_textEditorType);
|
||||||
|
if (editorType != null)
|
||||||
|
{
|
||||||
|
builder.OpenComponent(0, editorType);
|
||||||
|
|
||||||
|
var attributes = new Dictionary<string, object>
|
||||||
|
{
|
||||||
|
{ "Placeholder", Placeholder },
|
||||||
|
{ "ReadOnly", ReadOnly }
|
||||||
|
};
|
||||||
|
|
||||||
|
if (AdditionalAttributes != null)
|
||||||
|
{
|
||||||
|
foreach(var key in AdditionalAttributes.Keys)
|
||||||
|
{
|
||||||
|
if(!attributes.ContainsKey(key))
|
||||||
|
{
|
||||||
|
attributes.Add(key, AdditionalAttributes[key]);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
var richhtml = "";
|
attributes[key] = AdditionalAttributes[key];
|
||||||
|
|
||||||
if (AllowRichText)
|
|
||||||
{
|
|
||||||
richhtml = await interop.GetHtml(_editorElement);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (richhtml != _originalrichhtml && !string.IsNullOrEmpty(richhtml))
|
|
||||||
{
|
|
||||||
// convert Quill's empty content to empty string
|
|
||||||
if (richhtml == "<p><br></p>")
|
|
||||||
{
|
|
||||||
richhtml = string.Empty;
|
|
||||||
}
|
|
||||||
return richhtml;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// return original raw html content
|
|
||||||
return _originalrawhtml;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task InsertRichImage()
|
var index = 1;
|
||||||
|
foreach(var name in attributes.Keys)
|
||||||
{
|
{
|
||||||
_message = string.Empty;
|
if (editorType.GetProperty(name) != null)
|
||||||
if (_richfilemanager)
|
|
||||||
{
|
{
|
||||||
var file = _fileManager.GetFile();
|
builder.AddAttribute(index++, name, attributes[name]);
|
||||||
if (file != null)
|
|
||||||
{
|
|
||||||
await interop.InsertImage(_editorElement, file.Url, ((!string.IsNullOrEmpty(file.Description)) ? file.Description : file.Name));
|
|
||||||
_richhtml = await interop.GetHtml(_editorElement);
|
|
||||||
_richfilemanager = false;
|
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
_message = Localizer["Message.Require.Image"];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
_richfilemanager = true;
|
|
||||||
}
|
|
||||||
StateHasChanged();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task InsertRawImage()
|
builder.AddComponentReferenceCapture(index, (c) =>
|
||||||
{
|
{
|
||||||
_message = string.Empty;
|
_textEditor = (ITextEditor)c;
|
||||||
if (_rawfilemanager)
|
});
|
||||||
{
|
builder.CloseComponent();
|
||||||
var file = _fileManager.GetFile();
|
|
||||||
if (file != null)
|
|
||||||
{
|
|
||||||
var interop = new Interop(JSRuntime);
|
|
||||||
int pos = await interop.GetCaretPosition(_rawhtmlid);
|
|
||||||
var image = "<img src=\"" + file.Url + "\" alt=\"" + ((!string.IsNullOrEmpty(file.Description)) ? file.Description : file.Name) + "\" class=\"img-fluid\">";
|
|
||||||
_rawhtml = _rawhtml.Substring(0, pos) + image + _rawhtml.Substring(pos);
|
|
||||||
_rawfilemanager = false;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
_message = Localizer["Message.Require.Image"];
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
_rawfilemanager = true;
|
|
||||||
}
|
}
|
||||||
StateHasChanged();
|
|
||||||
|
private string GetTextEditorType()
|
||||||
|
{
|
||||||
|
const string EditorSettingName = "TextEditor";
|
||||||
|
|
||||||
|
if(!string.IsNullOrEmpty(Provider))
|
||||||
|
{
|
||||||
|
var provider = ServiceProvider.GetServices<ITextEditor>().FirstOrDefault(i => i.Name.Equals(Provider, StringComparison.OrdinalIgnoreCase));
|
||||||
|
if(provider != null)
|
||||||
|
{
|
||||||
|
return Utilities.GetFullTypeName(provider.GetType().AssemblyQualifiedName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return SettingService.GetSetting(PageState.Site.Settings, EditorSettingName, Constants.DefaultTextEditor);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -23,7 +23,7 @@
|
|||||||
</li>
|
</li>
|
||||||
}
|
}
|
||||||
</ul>
|
</ul>
|
||||||
<div class="tab-content">
|
<div class="tab-content @TabContentClass">
|
||||||
<br />
|
<br />
|
||||||
@ChildContent
|
@ChildContent
|
||||||
</div>
|
</div>
|
||||||
@ -47,6 +47,9 @@
|
|||||||
[Parameter]
|
[Parameter]
|
||||||
public string Id { get; set; } // optional - used to uniquely identify an instance of a tab strip component (will be set automatically if no value provided)
|
public string Id { get; set; } // optional - used to uniquely identify an instance of a tab strip component (will be set automatically if no value provided)
|
||||||
|
|
||||||
|
[Parameter]
|
||||||
|
public string TabContentClass { get; set; } // optional - to extend the TabContent div.
|
||||||
|
|
||||||
protected override void OnInitialized()
|
protected override void OnInitialized()
|
||||||
{
|
{
|
||||||
if (string.IsNullOrEmpty(Id))
|
if (string.IsNullOrEmpty(Id))
|
||||||
|
33
Oqtane.Client/Modules/Controls/TextAreaTextEditor.razor
Normal file
33
Oqtane.Client/Modules/Controls/TextAreaTextEditor.razor
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
@namespace Oqtane.Modules.Controls
|
||||||
|
@inherits ModuleControlBase
|
||||||
|
@implements ITextEditor
|
||||||
|
|
||||||
|
<div class="text-area-editor">
|
||||||
|
<textarea @bind="_content" @ref="_editor" placeholder="@Placeholder" readonly="@ReadOnly" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
@code {
|
||||||
|
public string Name => "TextArea";
|
||||||
|
|
||||||
|
private ElementReference _editor;
|
||||||
|
private string _content;
|
||||||
|
|
||||||
|
[Parameter]
|
||||||
|
public bool ReadOnly { get; set; }
|
||||||
|
|
||||||
|
[Parameter]
|
||||||
|
public string Placeholder { get; set; }
|
||||||
|
|
||||||
|
public void Initialize(string content)
|
||||||
|
{
|
||||||
|
_content = content;
|
||||||
|
|
||||||
|
StateHasChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<string> GetContent()
|
||||||
|
{
|
||||||
|
await Task.CompletedTask;
|
||||||
|
return _content;
|
||||||
|
}
|
||||||
|
}
|
@ -13,7 +13,7 @@
|
|||||||
<TabPanel Name="Edit" Heading="Edit" ResourceKey="Edit">
|
<TabPanel Name="Edit" Heading="Edit" ResourceKey="Edit">
|
||||||
@if (_content != null)
|
@if (_content != null)
|
||||||
{
|
{
|
||||||
<RichTextEditor Content="@_content" AllowFileManagement="@_allowfilemanagement" AllowRawHtml="@_allowrawhtml" @ref="@RichTextEditorHtml"></RichTextEditor>
|
<RichTextEditor Content="@_content" @ref="@RichTextEditorHtml"></RichTextEditor>
|
||||||
<br />
|
<br />
|
||||||
<button type="button" class="btn btn-success" @onclick="SaveContent">@SharedLocalizer["Save"]</button>
|
<button type="button" class="btn btn-success" @onclick="SaveContent">@SharedLocalizer["Save"]</button>
|
||||||
<NavLink class="btn btn-secondary" href="@NavigateUrl()">@SharedLocalizer["Cancel"]</NavLink>
|
<NavLink class="btn btn-secondary" href="@NavigateUrl()">@SharedLocalizer["Cancel"]</NavLink>
|
||||||
@ -51,15 +51,7 @@
|
|||||||
|
|
||||||
public override string Title => "Edit Html/Text";
|
public override string Title => "Edit Html/Text";
|
||||||
|
|
||||||
public override List<Resource> Resources => new List<Resource>()
|
|
||||||
{
|
|
||||||
new Resource { ResourceType = ResourceType.Stylesheet, Url = "css/quill/quill.bubble.css" },
|
|
||||||
new Resource { ResourceType = ResourceType.Stylesheet, Url = "css/quill/quill.snow.css" }
|
|
||||||
};
|
|
||||||
|
|
||||||
private RichTextEditor RichTextEditorHtml;
|
private RichTextEditor RichTextEditorHtml;
|
||||||
private bool _allowfilemanagement;
|
|
||||||
private bool _allowrawhtml;
|
|
||||||
private string _content = null;
|
private string _content = null;
|
||||||
private string _createdby;
|
private string _createdby;
|
||||||
private DateTime _createdon;
|
private DateTime _createdon;
|
||||||
@ -72,8 +64,6 @@
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
_allowfilemanagement = bool.Parse(SettingService.GetSetting(ModuleState.Settings, "AllowFileManagement", "true"));
|
|
||||||
_allowrawhtml = bool.Parse(SettingService.GetSetting(ModuleState.Settings, "AllowRawHtml", "true"));
|
|
||||||
await LoadContent();
|
await LoadContent();
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
|
@ -37,6 +37,10 @@
|
|||||||
content = htmltext.Content;
|
content = htmltext.Content;
|
||||||
content = Utilities.FormatContent(content, PageState.Alias, "render");
|
content = Utilities.FormatContent(content, PageState.Alias, "render");
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
content = "";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
|
@ -15,7 +15,7 @@ namespace Oqtane.Modules.HtmlText
|
|||||||
Version = "1.0.1",
|
Version = "1.0.1",
|
||||||
ServerManagerType = "Oqtane.Modules.HtmlText.Manager.HtmlTextManager, Oqtane.Server",
|
ServerManagerType = "Oqtane.Modules.HtmlText.Manager.HtmlTextManager, Oqtane.Server",
|
||||||
ReleaseVersions = "1.0.0,1.0.1",
|
ReleaseVersions = "1.0.0,1.0.1",
|
||||||
SettingsType = "Oqtane.Modules.HtmlText.Settings, Oqtane.Client",
|
SettingsType = string.Empty,
|
||||||
Resources = new List<Resource>()
|
Resources = new List<Resource>()
|
||||||
{
|
{
|
||||||
new Resource { ResourceType = ResourceType.Stylesheet, Url = "~/Module.css" }
|
new Resource { ResourceType = ResourceType.Stylesheet, Url = "~/Module.css" }
|
||||||
|
@ -1,61 +0,0 @@
|
|||||||
@namespace Oqtane.Modules.HtmlText
|
|
||||||
@inherits ModuleBase
|
|
||||||
@inject ISettingService SettingService
|
|
||||||
@implements Oqtane.Interfaces.ISettingsControl
|
|
||||||
@inject IStringLocalizer<Settings> Localizer
|
|
||||||
@inject IStringLocalizer<SharedResources> SharedLocalizer
|
|
||||||
|
|
||||||
<div class="container">
|
|
||||||
<div class="row mb-1 align-items-center">
|
|
||||||
<Label Class="col-sm-3" For="files" ResourceKey="AllowFileManagement" ResourceType="@resourceType" HelpText="Specify If Editors Can Upload and Select Files">Allow File Management: </Label>
|
|
||||||
<div class="col-sm-9">
|
|
||||||
<select id="files" class="form-select" @bind="@_allowfilemanagement">
|
|
||||||
<option value="true">@SharedLocalizer["Yes"]</option>
|
|
||||||
<option value="false">@SharedLocalizer["No"]</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="row mb-1 align-items-center">
|
|
||||||
<Label Class="col-sm-3" For="files" ResourceKey="AllowRawHtml" ResourceType="@resourceType" HelpText="Specify If Editors Can Enter Raw HTML">Allow Raw HTML: </Label>
|
|
||||||
<div class="col-sm-9">
|
|
||||||
<select id="files" class="form-select" @bind="@_allowrawhtml">
|
|
||||||
<option value="true">@SharedLocalizer["Yes"]</option>
|
|
||||||
<option value="false">@SharedLocalizer["No"]</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
@code {
|
|
||||||
private string resourceType = "Oqtane.Modules.HtmlText.Settings, Oqtane.Client"; // for localization
|
|
||||||
private string _allowfilemanagement;
|
|
||||||
private string _allowrawhtml;
|
|
||||||
|
|
||||||
protected override void OnInitialized()
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
_allowfilemanagement = SettingService.GetSetting(ModuleState.Settings, "AllowFileManagement", "true");
|
|
||||||
_allowrawhtml = SettingService.GetSetting(ModuleState.Settings, "AllowRawHtml", "true");
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
AddModuleMessage(ex.Message, MessageType.Error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task UpdateSettings()
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var settings = await SettingService.GetModuleSettingsAsync(ModuleState.ModuleId);
|
|
||||||
settings = SettingService.SetSetting(settings, "AllowFileManagement", _allowfilemanagement);
|
|
||||||
settings = SettingService.SetSetting(settings, "AllowRawHtml", _allowrawhtml);
|
|
||||||
await SettingService.UpdateModuleSettingsAsync(settings, ModuleState.ModuleId);
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
AddModuleMessage(ex.Message, MessageType.Error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -52,6 +52,8 @@ namespace Oqtane.Modules
|
|||||||
|
|
||||||
public virtual string RenderMode { get { return RenderModes.Interactive; } } // interactive by default
|
public virtual string RenderMode { get { return RenderModes.Interactive; } } // interactive by default
|
||||||
|
|
||||||
|
public virtual bool? Prerender { get { return null; } } // allows the Site Prerender property to be overridden
|
||||||
|
|
||||||
// url parameters
|
// url parameters
|
||||||
public virtual string UrlParametersTemplate { get; set; }
|
public virtual string UrlParametersTemplate { get; set; }
|
||||||
|
|
||||||
@ -276,7 +278,6 @@ namespace Oqtane.Modules
|
|||||||
|
|
||||||
public void AddModuleMessage(string message, MessageType type, string position)
|
public void AddModuleMessage(string message, MessageType type, string position)
|
||||||
{
|
{
|
||||||
ClearModuleMessage();
|
|
||||||
RenderModeBoundary.AddModuleMessage(message, type, position);
|
RenderModeBoundary.AddModuleMessage(message, type, position);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
<TargetFramework>net8.0</TargetFramework>
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
<OutputType>Exe</OutputType>
|
<OutputType>Exe</OutputType>
|
||||||
<Configurations>Debug;Release</Configurations>
|
<Configurations>Debug;Release</Configurations>
|
||||||
<Version>5.1.1</Version>
|
<Version>5.2.1</Version>
|
||||||
<Product>Oqtane</Product>
|
<Product>Oqtane</Product>
|
||||||
<Authors>Shaun Walker</Authors>
|
<Authors>Shaun Walker</Authors>
|
||||||
<Company>.NET Foundation</Company>
|
<Company>.NET Foundation</Company>
|
||||||
@ -12,7 +12,7 @@
|
|||||||
<Copyright>.NET Foundation</Copyright>
|
<Copyright>.NET Foundation</Copyright>
|
||||||
<PackageProjectUrl>https://www.oqtane.org</PackageProjectUrl>
|
<PackageProjectUrl>https://www.oqtane.org</PackageProjectUrl>
|
||||||
<PackageLicenseUrl>https://github.com/oqtane/oqtane.framework/blob/dev/LICENSE</PackageLicenseUrl>
|
<PackageLicenseUrl>https://github.com/oqtane/oqtane.framework/blob/dev/LICENSE</PackageLicenseUrl>
|
||||||
<PackageReleaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v5.1.1</PackageReleaseNotes>
|
<PackageReleaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v5.2.1</PackageReleaseNotes>
|
||||||
<RepositoryUrl>https://github.com/oqtane/oqtane.framework</RepositoryUrl>
|
<RepositoryUrl>https://github.com/oqtane/oqtane.framework</RepositoryUrl>
|
||||||
<RepositoryType>Git</RepositoryType>
|
<RepositoryType>Git</RepositoryType>
|
||||||
<RootNamespace>Oqtane</RootNamespace>
|
<RootNamespace>Oqtane</RootNamespace>
|
||||||
@ -22,9 +22,9 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="8.0.4" />
|
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="8.0.8" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.Authentication" Version="8.0.4" />
|
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.Authentication" Version="8.0.8" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Localization" Version="8.0.4" />
|
<PackageReference Include="Microsoft.Extensions.Localization" Version="8.0.8" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Http" Version="8.0.0" />
|
<PackageReference Include="Microsoft.Extensions.Http" Version="8.0.0" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Localization" Version="2.2.0" />
|
<PackageReference Include="Microsoft.AspNetCore.Localization" Version="2.2.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
@ -150,14 +150,11 @@
|
|||||||
<data name="Name.HelpText" xml:space="preserve">
|
<data name="Name.HelpText" xml:space="preserve">
|
||||||
<value>Enter the folder name</value>
|
<value>Enter the folder name</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="Permissions.HelpText" xml:space="preserve">
|
|
||||||
<value>Select the permissions you want for the folder</value>
|
|
||||||
</data>
|
|
||||||
<data name="Parent.Text" xml:space="preserve">
|
<data name="Parent.Text" xml:space="preserve">
|
||||||
<value>Parent: </value>
|
<value>Parent: </value>
|
||||||
</data>
|
</data>
|
||||||
<data name="Permissions.Text" xml:space="preserve">
|
<data name="Permissions.Heading" xml:space="preserve">
|
||||||
<value>Permissions: </value>
|
<value>Permissions</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="DeleteFolder.Header" xml:space="preserve">
|
<data name="DeleteFolder.Header" xml:space="preserve">
|
||||||
<value>Delete Folder</value>
|
<value>Delete Folder</value>
|
||||||
@ -195,4 +192,10 @@
|
|||||||
<data name="Folder Management" xml:space="preserve">
|
<data name="Folder Management" xml:space="preserve">
|
||||||
<value>Folder Management</value>
|
<value>Folder Management</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="Message.Folder.Duplicate" xml:space="preserve">
|
||||||
|
<value>Folder Name Specified Already Exists In Parent</value>
|
||||||
|
</data>
|
||||||
|
<data name="Settings.Heading" xml:space="preserve">
|
||||||
|
<value>Settings</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
@ -144,8 +144,8 @@
|
|||||||
<data name="Month" xml:space="preserve">
|
<data name="Month" xml:space="preserve">
|
||||||
<value>Month(s)</value>
|
<value>Month(s)</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="ViewJobs.Text" xml:space="preserve">
|
<data name="ViewLogs.Text" xml:space="preserve">
|
||||||
<value>View Logs</value>
|
<value>View All Logs</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="Frequency" xml:space="preserve">
|
<data name="Frequency" xml:space="preserve">
|
||||||
<value>Frequency</value>
|
<value>Frequency</value>
|
||||||
|
@ -132,4 +132,7 @@
|
|||||||
<data name="Failed" xml:space="preserve">
|
<data name="Failed" xml:space="preserve">
|
||||||
<value>Failed</value>
|
<value>Failed</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="Refresh" xml:space="preserve">
|
||||||
|
<value>Refresh</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
@ -156,7 +156,7 @@
|
|||||||
<data name="Module.Text" xml:space="preserve">
|
<data name="Module.Text" xml:space="preserve">
|
||||||
<value>Module:</value>
|
<value>Module:</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="Module Settings" xml:space="preserve">
|
<data name="ModuleSettings.Heading" xml:space="preserve">
|
||||||
<value>Module Settings</value>
|
<value>Module Settings</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="Pane.HelpText" xml:space="preserve">
|
<data name="Pane.HelpText" xml:space="preserve">
|
||||||
@ -177,4 +177,16 @@
|
|||||||
<data name="ExpiryDate.Text" xml:space="preserve">
|
<data name="ExpiryDate.Text" xml:space="preserve">
|
||||||
<value>Expiry Date: </value>
|
<value>Expiry Date: </value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="Permissions.Text" xml:space="preserve">
|
||||||
|
<value>Permissions</value>
|
||||||
|
</data>
|
||||||
|
<data name="Permissions.Heading" xml:space="preserve">
|
||||||
|
<value>Permissions</value>
|
||||||
|
</data>
|
||||||
|
<data name="ContainerSettings.Heading" xml:space="preserve">
|
||||||
|
<value>Container Settings</value>
|
||||||
|
</data>
|
||||||
|
<data name="ModuleSettings.Title" xml:space="preserve">
|
||||||
|
<value>Module Settings</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
@ -138,4 +138,7 @@
|
|||||||
<data name="EditPage.Text" xml:space="preserve">
|
<data name="EditPage.Text" xml:space="preserve">
|
||||||
<value>Edit</value>
|
<value>Edit</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="Error.Page.Load" xml:space="preserve">
|
||||||
|
<value>Error Loading Pages</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
@ -147,4 +147,7 @@
|
|||||||
<data name="Title" xml:space="preserve">
|
<data name="Title" xml:space="preserve">
|
||||||
<value>Title</value>
|
<value>Title</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="Detail.Text" xml:space="preserve">
|
||||||
|
<value>Detail</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
180
Oqtane.Client/Resources/Modules/Admin/Search/Index.resx
Normal file
180
Oqtane.Client/Resources/Modules/Admin/Search/Index.resx
Normal file
@ -0,0 +1,180 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<root>
|
||||||
|
<!--
|
||||||
|
Microsoft ResX Schema
|
||||||
|
|
||||||
|
Version 2.0
|
||||||
|
|
||||||
|
The primary goals of this format is to allow a simple XML format
|
||||||
|
that is mostly human readable. The generation and parsing of the
|
||||||
|
various data types are done through the TypeConverter classes
|
||||||
|
associated with the data types.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
... ado.net/XML headers & schema ...
|
||||||
|
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||||
|
<resheader name="version">2.0</resheader>
|
||||||
|
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||||
|
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||||
|
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||||
|
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||||
|
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||||
|
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||||
|
</data>
|
||||||
|
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||||
|
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||||
|
<comment>This is a comment</comment>
|
||||||
|
</data>
|
||||||
|
|
||||||
|
There are any number of "resheader" rows that contain simple
|
||||||
|
name/value pairs.
|
||||||
|
|
||||||
|
Each data row contains a name, and value. The row also contains a
|
||||||
|
type or mimetype. Type corresponds to a .NET class that support
|
||||||
|
text/value conversion through the TypeConverter architecture.
|
||||||
|
Classes that don't support this are serialized and stored with the
|
||||||
|
mimetype set.
|
||||||
|
|
||||||
|
The mimetype is used for serialized objects, and tells the
|
||||||
|
ResXResourceReader how to depersist the object. This is currently not
|
||||||
|
extensible. For a given mimetype the value must be set accordingly:
|
||||||
|
|
||||||
|
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||||
|
that the ResXResourceWriter will generate, however the reader can
|
||||||
|
read any of the formats listed below.
|
||||||
|
|
||||||
|
mimetype: application/x-microsoft.net.object.binary.base64
|
||||||
|
value : The object must be serialized with
|
||||||
|
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||||
|
: and then encoded with base64 encoding.
|
||||||
|
|
||||||
|
mimetype: application/x-microsoft.net.object.soap.base64
|
||||||
|
value : The object must be serialized with
|
||||||
|
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||||
|
: and then encoded with base64 encoding.
|
||||||
|
|
||||||
|
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||||
|
value : The object must be serialized into a byte array
|
||||||
|
: using a System.ComponentModel.TypeConverter
|
||||||
|
: and then encoded with base64 encoding.
|
||||||
|
-->
|
||||||
|
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||||
|
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||||
|
<xsd:element name="root" msdata:IsDataSet="true">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:choice maxOccurs="unbounded">
|
||||||
|
<xsd:element name="metadata">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||||
|
</xsd:sequence>
|
||||||
|
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||||
|
<xsd:attribute name="type" type="xsd:string" />
|
||||||
|
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||||
|
<xsd:attribute ref="xml:space" />
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
<xsd:element name="assembly">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:attribute name="alias" type="xsd:string" />
|
||||||
|
<xsd:attribute name="name" type="xsd:string" />
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
<xsd:element name="data">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||||
|
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||||
|
</xsd:sequence>
|
||||||
|
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||||
|
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||||
|
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||||
|
<xsd:attribute ref="xml:space" />
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
<xsd:element name="resheader">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||||
|
</xsd:sequence>
|
||||||
|
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
</xsd:choice>
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
</xsd:schema>
|
||||||
|
<resheader name="resmimetype">
|
||||||
|
<value>text/microsoft-resx</value>
|
||||||
|
</resheader>
|
||||||
|
<resheader name="version">
|
||||||
|
<value>2.0</value>
|
||||||
|
</resheader>
|
||||||
|
<resheader name="reader">
|
||||||
|
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||||
|
</resheader>
|
||||||
|
<resheader name="writer">
|
||||||
|
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||||
|
</resheader>
|
||||||
|
<data name="Enabled.Text" xml:space="preserve">
|
||||||
|
<value>Enabled? </value>
|
||||||
|
</data>
|
||||||
|
<data name="Enabled.HelpText" xml:space="preserve">
|
||||||
|
<value>Specify if search indexing is enabled</value>
|
||||||
|
</data>
|
||||||
|
<data name="LastIndexedOn.Text" xml:space="preserve">
|
||||||
|
<value>Last Indexed: </value>
|
||||||
|
</data>
|
||||||
|
<data name="LastIndexedOn.HelpText" xml:space="preserve">
|
||||||
|
<value>The date/time which the site was last indexed on</value>
|
||||||
|
</data>
|
||||||
|
<data name="IgnorePages.Text" xml:space="preserve">
|
||||||
|
<value>Ignore Pages: </value>
|
||||||
|
</data>
|
||||||
|
<data name="IgnorePages.HelpText" xml:space="preserve">
|
||||||
|
<value>Comma delimited list of pages which should be ignored (based on page path)</value>
|
||||||
|
</data>
|
||||||
|
<data name="IgnoreEntities.Text" xml:space="preserve">
|
||||||
|
<value>Ignore Entities: </value>
|
||||||
|
</data>
|
||||||
|
<data name="IgnoreEntities.HelpText" xml:space="preserve">
|
||||||
|
<value>Comma delimited list of entities which should be ignored</value>
|
||||||
|
</data>
|
||||||
|
<data name="MinimumWordLength.Text" xml:space="preserve">
|
||||||
|
<value>Word Length: </value>
|
||||||
|
</data>
|
||||||
|
<data name="MinimumWordLength.HelpText" xml:space="preserve">
|
||||||
|
<value>Minimum length of a word to be indexed</value>
|
||||||
|
</data>
|
||||||
|
<data name="IgnoreWords.Text" xml:space="preserve">
|
||||||
|
<value>Ignore Words: </value>
|
||||||
|
</data>
|
||||||
|
<data name="IgnoreWords.HelpText" xml:space="preserve">
|
||||||
|
<value>Comma delimited list of words which should be ignored</value>
|
||||||
|
</data>
|
||||||
|
<data name="Success.Save" xml:space="preserve">
|
||||||
|
<value>Search Settings Saved Successfully</value>
|
||||||
|
</data>
|
||||||
|
<data name="Error.Save" xml:space="preserve">
|
||||||
|
<value>Error Saving Search Settings</value>
|
||||||
|
</data>
|
||||||
|
<data name="SearchProvider.HelpText" xml:space="preserve">
|
||||||
|
<value>Specify the search provider for this site</value>
|
||||||
|
</data>
|
||||||
|
<data name="SearchProvider.Text" xml:space="preserve">
|
||||||
|
<value>Search Provider:</value>
|
||||||
|
</data>
|
||||||
|
<data name="Message.Reindex" xml:space="preserve">
|
||||||
|
<value>The search index will be rebuilt for this site. Please be patient during the reindexing process.</value>
|
||||||
|
</data>
|
||||||
|
<data name="Reindex.Text" xml:space="preserve">
|
||||||
|
<value>Reindex</value>
|
||||||
|
</data>
|
||||||
|
<data name="Reindex.Header" xml:space="preserve">
|
||||||
|
<value>Reindex</value>
|
||||||
|
</data>
|
||||||
|
<data name="Reindex.Message" xml:space="preserve">
|
||||||
|
<value>Are You Sure You Wish To Reindex Search Content?</value>
|
||||||
|
</data>
|
||||||
|
</root>
|
@ -1,4 +1,4 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<root>
|
<root>
|
||||||
<!--
|
<!--
|
||||||
Microsoft ResX Schema
|
Microsoft ResX Schema
|
||||||
@ -117,16 +117,16 @@
|
|||||||
<resheader name="writer">
|
<resheader name="writer">
|
||||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||||
</resheader>
|
</resheader>
|
||||||
<data name="AllowFileManagement.HelpText" xml:space="preserve">
|
<data name="NoCriteria" xml:space="preserve">
|
||||||
<value>Specify If Editors Can Upload and Select Files</value>
|
<value>You Must Provide Some Search Criteria</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="AllowFileManagement.Text" xml:space="preserve">
|
<data name="NoResult" xml:space="preserve">
|
||||||
<value>Allow File Management: </value>
|
<value>No Content Matches The Criteria Provided</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="AllowRawHtml.HelpText" xml:space="preserve">
|
<data name="SearchLabel" xml:space="preserve">
|
||||||
<value>Specify If Editors Can Enter Raw HTML</value>
|
<value>Search:</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="AllowRawHtml.Text" xml:space="preserve">
|
<data name="SearchPlaceholder" xml:space="preserve">
|
||||||
<value>Allow Raw HTML:</value>
|
<value>Search</value>
|
||||||
</data>
|
</data>
|
||||||
</root>
|
</root>
|
@ -0,0 +1,180 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<root>
|
||||||
|
<!--
|
||||||
|
Microsoft ResX Schema
|
||||||
|
|
||||||
|
Version 2.0
|
||||||
|
|
||||||
|
The primary goals of this format is to allow a simple XML format
|
||||||
|
that is mostly human readable. The generation and parsing of the
|
||||||
|
various data types are done through the TypeConverter classes
|
||||||
|
associated with the data types.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
... ado.net/XML headers & schema ...
|
||||||
|
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||||
|
<resheader name="version">2.0</resheader>
|
||||||
|
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||||
|
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||||
|
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||||
|
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||||
|
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||||
|
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||||
|
</data>
|
||||||
|
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||||
|
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||||
|
<comment>This is a comment</comment>
|
||||||
|
</data>
|
||||||
|
|
||||||
|
There are any number of "resheader" rows that contain simple
|
||||||
|
name/value pairs.
|
||||||
|
|
||||||
|
Each data row contains a name, and value. The row also contains a
|
||||||
|
type or mimetype. Type corresponds to a .NET class that support
|
||||||
|
text/value conversion through the TypeConverter architecture.
|
||||||
|
Classes that don't support this are serialized and stored with the
|
||||||
|
mimetype set.
|
||||||
|
|
||||||
|
The mimetype is used for serialized objects, and tells the
|
||||||
|
ResXResourceReader how to depersist the object. This is currently not
|
||||||
|
extensible. For a given mimetype the value must be set accordingly:
|
||||||
|
|
||||||
|
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||||
|
that the ResXResourceWriter will generate, however the reader can
|
||||||
|
read any of the formats listed below.
|
||||||
|
|
||||||
|
mimetype: application/x-microsoft.net.object.binary.base64
|
||||||
|
value : The object must be serialized with
|
||||||
|
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||||
|
: and then encoded with base64 encoding.
|
||||||
|
|
||||||
|
mimetype: application/x-microsoft.net.object.soap.base64
|
||||||
|
value : The object must be serialized with
|
||||||
|
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||||
|
: and then encoded with base64 encoding.
|
||||||
|
|
||||||
|
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||||
|
value : The object must be serialized into a byte array
|
||||||
|
: using a System.ComponentModel.TypeConverter
|
||||||
|
: and then encoded with base64 encoding.
|
||||||
|
-->
|
||||||
|
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||||
|
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||||
|
<xsd:element name="root" msdata:IsDataSet="true">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:choice maxOccurs="unbounded">
|
||||||
|
<xsd:element name="metadata">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||||
|
</xsd:sequence>
|
||||||
|
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||||
|
<xsd:attribute name="type" type="xsd:string" />
|
||||||
|
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||||
|
<xsd:attribute ref="xml:space" />
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
<xsd:element name="assembly">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:attribute name="alias" type="xsd:string" />
|
||||||
|
<xsd:attribute name="name" type="xsd:string" />
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
<xsd:element name="data">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||||
|
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||||
|
</xsd:sequence>
|
||||||
|
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||||
|
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||||
|
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||||
|
<xsd:attribute ref="xml:space" />
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
<xsd:element name="resheader">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||||
|
</xsd:sequence>
|
||||||
|
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
</xsd:choice>
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
</xsd:schema>
|
||||||
|
<resheader name="resmimetype">
|
||||||
|
<value>text/microsoft-resx</value>
|
||||||
|
</resheader>
|
||||||
|
<resheader name="version">
|
||||||
|
<value>2.0</value>
|
||||||
|
</resheader>
|
||||||
|
<resheader name="reader">
|
||||||
|
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||||
|
</resheader>
|
||||||
|
<resheader name="writer">
|
||||||
|
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||||
|
</resheader>
|
||||||
|
<data name="Ascending" xml:space="preserve">
|
||||||
|
<value>Ascending</value>
|
||||||
|
</data>
|
||||||
|
<data name="BodyLength.HelpText" xml:space="preserve">
|
||||||
|
<value>The number of characters displayed for each search result summary. The default is 255 characters.</value>
|
||||||
|
</data>
|
||||||
|
<data name="BodyLength.Text" xml:space="preserve">
|
||||||
|
<value>Body Size:</value>
|
||||||
|
</data>
|
||||||
|
<data name="DateRange.HelpText" xml:space="preserve">
|
||||||
|
<value>Enter the date range for search results. The default includes all content.</value>
|
||||||
|
</data>
|
||||||
|
<data name="DateRange.Text" xml:space="preserve">
|
||||||
|
<value>Date Range:</value>
|
||||||
|
</data>
|
||||||
|
<data name="Descending" xml:space="preserve">
|
||||||
|
<value>Descending</value>
|
||||||
|
</data>
|
||||||
|
<data name="ExcludeEntities.HelpText" xml:space="preserve">
|
||||||
|
<value>Comma delimited list of entities to exclude from search results. By default no entities will be excluded.</value>
|
||||||
|
</data>
|
||||||
|
<data name="ExcludeEntities.Text" xml:space="preserve">
|
||||||
|
<value>Exlude Entities:</value>
|
||||||
|
</data>
|
||||||
|
<data name="IncludeEntities.HelpText" xml:space="preserve">
|
||||||
|
<value>Comma delimited list of entities to include in the search results. By default all entities will be included.</value>
|
||||||
|
</data>
|
||||||
|
<data name="IncludeEntities.Text" xml:space="preserve">
|
||||||
|
<value>Include Entities:</value>
|
||||||
|
</data>
|
||||||
|
<data name="LastModified" xml:space="preserve">
|
||||||
|
<value>LastModified</value>
|
||||||
|
</data>
|
||||||
|
<data name="PageSize.HelpText" xml:space="preserve">
|
||||||
|
<value>The maximum number of search results to retrieve. The default is unlimited.</value>
|
||||||
|
</data>
|
||||||
|
<data name="PageSize.Text" xml:space="preserve">
|
||||||
|
<value>Page Size:</value>
|
||||||
|
</data>
|
||||||
|
<data name="Relevance" xml:space="preserve">
|
||||||
|
<value>Relevance</value>
|
||||||
|
</data>
|
||||||
|
<data name="SortField.HelpText" xml:space="preserve">
|
||||||
|
<value>Specify the default sort field</value>
|
||||||
|
</data>
|
||||||
|
<data name="SortField.Text" xml:space="preserve">
|
||||||
|
<value>Sort By:</value>
|
||||||
|
</data>
|
||||||
|
<data name="SortOrder.HelpText" xml:space="preserve">
|
||||||
|
<value>Specify the default sort order</value>
|
||||||
|
</data>
|
||||||
|
<data name="SortOrder.Text" xml:space="preserve">
|
||||||
|
<value>Sort Order:</value>
|
||||||
|
</data>
|
||||||
|
<data name="Title" xml:space="preserve">
|
||||||
|
<value>Title</value>
|
||||||
|
</data>
|
||||||
|
<data name="To" xml:space="preserve">
|
||||||
|
<value>To</value>
|
||||||
|
</data>
|
||||||
|
</root>
|
@ -277,10 +277,10 @@
|
|||||||
<value>UI Component Settings</value>
|
<value>UI Component Settings</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="Prerender.HelpText" xml:space="preserve">
|
<data name="Prerender.HelpText" xml:space="preserve">
|
||||||
<value>Specifies if interactive components should prerender their output</value>
|
<value>Specifies if interactive components should prerender their output on the server</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="Prerender.Text" xml:space="preserve">
|
<data name="Prerender.Text" xml:space="preserve">
|
||||||
<value>Prerender? </value>
|
<value>Prerender: </value>
|
||||||
</data>
|
</data>
|
||||||
<data name="RenderMode.HelpText" xml:space="preserve">
|
<data name="RenderMode.HelpText" xml:space="preserve">
|
||||||
<value>The default render mode for the site</value>
|
<value>The default render mode for the site</value>
|
||||||
@ -402,9 +402,6 @@
|
|||||||
<data name="Retention.Text" xml:space="preserve">
|
<data name="Retention.Text" xml:space="preserve">
|
||||||
<value>Retention (Days):</value>
|
<value>Retention (Days):</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="FileExtensions.Heading" xml:space="preserve">
|
|
||||||
<value>File Extensions</value>
|
|
||||||
</data>
|
|
||||||
<data name="ImageExtensions.HelpText" xml:space="preserve">
|
<data name="ImageExtensions.HelpText" xml:space="preserve">
|
||||||
<value>Enter a comma separated list of image file extensions</value>
|
<value>Enter a comma separated list of image file extensions</value>
|
||||||
</data>
|
</data>
|
||||||
@ -429,4 +426,13 @@
|
|||||||
<data name="Runtime.Text" xml:space="preserve">
|
<data name="Runtime.Text" xml:space="preserve">
|
||||||
<value>Interactivity:</value>
|
<value>Interactivity:</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="TextEditor.HelpText" xml:space="preserve">
|
||||||
|
<value>Select the text editor for the site</value>
|
||||||
|
</data>
|
||||||
|
<data name="TextEditor.Text" xml:space="preserve">
|
||||||
|
<value>Text Editor:</value>
|
||||||
|
</data>
|
||||||
|
<data name="Functionality" xml:space="preserve">
|
||||||
|
<value>Functionality</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
@ -159,4 +159,7 @@
|
|||||||
<data name="Url" xml:space="preserve">
|
<data name="Url" xml:space="preserve">
|
||||||
<value>Url</value>
|
<value>Url</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="Edit.Text" xml:space="preserve">
|
||||||
|
<value>Edit</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
@ -184,7 +184,7 @@
|
|||||||
<value>Number of days of visitor activity to retain</value>
|
<value>Number of days of visitor activity to retain</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="Retention.Text" xml:space="preserve">
|
<data name="Retention.Text" xml:space="preserve">
|
||||||
<value>Retention (Days):</value>
|
<value>Retention:</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="Correlation.HelpText" xml:space="preserve">
|
<data name="Correlation.HelpText" xml:space="preserve">
|
||||||
<value>Indicate if new visitors to this site should be correlated based on their IP Address</value>
|
<value>Indicate if new visitors to this site should be correlated based on their IP Address</value>
|
||||||
@ -192,4 +192,10 @@
|
|||||||
<data name="Correlation.Text" xml:space="preserve">
|
<data name="Correlation.Text" xml:space="preserve">
|
||||||
<value>Correlate Visitors?</value>
|
<value>Correlate Visitors?</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="Duration.HelpText" xml:space="preserve">
|
||||||
|
<value>The duration of a browsing session considered to be a distinct visit (in minutes)</value>
|
||||||
|
</data>
|
||||||
|
<data name="Duration.Text" xml:space="preserve">
|
||||||
|
<value>Session Duration:</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
174
Oqtane.Client/Resources/Modules/Controls/QuillJSTextEditor.resx
Normal file
174
Oqtane.Client/Resources/Modules/Controls/QuillJSTextEditor.resx
Normal file
@ -0,0 +1,174 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<root>
|
||||||
|
<!--
|
||||||
|
Microsoft ResX Schema
|
||||||
|
|
||||||
|
Version 2.0
|
||||||
|
|
||||||
|
The primary goals of this format is to allow a simple XML format
|
||||||
|
that is mostly human readable. The generation and parsing of the
|
||||||
|
various data types are done through the TypeConverter classes
|
||||||
|
associated with the data types.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
... ado.net/XML headers & schema ...
|
||||||
|
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||||
|
<resheader name="version">2.0</resheader>
|
||||||
|
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||||
|
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||||
|
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||||
|
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||||
|
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||||
|
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||||
|
</data>
|
||||||
|
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||||
|
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||||
|
<comment>This is a comment</comment>
|
||||||
|
</data>
|
||||||
|
|
||||||
|
There are any number of "resheader" rows that contain simple
|
||||||
|
name/value pairs.
|
||||||
|
|
||||||
|
Each data row contains a name, and value. The row also contains a
|
||||||
|
type or mimetype. Type corresponds to a .NET class that support
|
||||||
|
text/value conversion through the TypeConverter architecture.
|
||||||
|
Classes that don't support this are serialized and stored with the
|
||||||
|
mimetype set.
|
||||||
|
|
||||||
|
The mimetype is used for serialized objects, and tells the
|
||||||
|
ResXResourceReader how to depersist the object. This is currently not
|
||||||
|
extensible. For a given mimetype the value must be set accordingly:
|
||||||
|
|
||||||
|
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||||
|
that the ResXResourceWriter will generate, however the reader can
|
||||||
|
read any of the formats listed below.
|
||||||
|
|
||||||
|
mimetype: application/x-microsoft.net.object.binary.base64
|
||||||
|
value : The object must be serialized with
|
||||||
|
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||||
|
: and then encoded with base64 encoding.
|
||||||
|
|
||||||
|
mimetype: application/x-microsoft.net.object.soap.base64
|
||||||
|
value : The object must be serialized with
|
||||||
|
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||||
|
: and then encoded with base64 encoding.
|
||||||
|
|
||||||
|
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||||
|
value : The object must be serialized into a byte array
|
||||||
|
: using a System.ComponentModel.TypeConverter
|
||||||
|
: and then encoded with base64 encoding.
|
||||||
|
-->
|
||||||
|
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||||
|
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||||
|
<xsd:element name="root" msdata:IsDataSet="true">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:choice maxOccurs="unbounded">
|
||||||
|
<xsd:element name="metadata">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||||
|
</xsd:sequence>
|
||||||
|
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||||
|
<xsd:attribute name="type" type="xsd:string" />
|
||||||
|
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||||
|
<xsd:attribute ref="xml:space" />
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
<xsd:element name="assembly">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:attribute name="alias" type="xsd:string" />
|
||||||
|
<xsd:attribute name="name" type="xsd:string" />
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
<xsd:element name="data">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||||
|
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||||
|
</xsd:sequence>
|
||||||
|
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||||
|
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||||
|
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||||
|
<xsd:attribute ref="xml:space" />
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
<xsd:element name="resheader">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||||
|
</xsd:sequence>
|
||||||
|
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
</xsd:choice>
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
</xsd:schema>
|
||||||
|
<resheader name="resmimetype">
|
||||||
|
<value>text/microsoft-resx</value>
|
||||||
|
</resheader>
|
||||||
|
<resheader name="version">
|
||||||
|
<value>2.0</value>
|
||||||
|
</resheader>
|
||||||
|
<resheader name="reader">
|
||||||
|
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||||
|
</resheader>
|
||||||
|
<resheader name="writer">
|
||||||
|
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||||
|
</resheader>
|
||||||
|
<data name="AllowFileManagement.HelpText" xml:space="preserve">
|
||||||
|
<value>Specify if editors can upload and insert images</value>
|
||||||
|
</data>
|
||||||
|
<data name="AllowFileManagement.Text" xml:space="preserve">
|
||||||
|
<value>Insert Images?</value>
|
||||||
|
</data>
|
||||||
|
<data name="AllowRawHtml.HelpText" xml:space="preserve">
|
||||||
|
<value>Specify if editors can use the Raw HTML Editor</value>
|
||||||
|
</data>
|
||||||
|
<data name="AllowRawHtml.Text" xml:space="preserve">
|
||||||
|
<value>Raw HTML Editor?</value>
|
||||||
|
</data>
|
||||||
|
<data name="AllowRichText.HelpText" xml:space="preserve">
|
||||||
|
<value>Specify if editors can use the Rich Text Editor</value>
|
||||||
|
</data>
|
||||||
|
<data name="AllowRichText.Text" xml:space="preserve">
|
||||||
|
<value>Rich Text Editor? </value>
|
||||||
|
</data>
|
||||||
|
<data name="Close" xml:space="preserve">
|
||||||
|
<value>Close</value>
|
||||||
|
</data>
|
||||||
|
<data name="DebugLevel.HelpText" xml:space="preserve">
|
||||||
|
<value>Specify the Debug Level</value>
|
||||||
|
</data>
|
||||||
|
<data name="DebugLevel.Text" xml:space="preserve">
|
||||||
|
<value>Debug Level:</value>
|
||||||
|
</data>
|
||||||
|
<data name="InsertImage" xml:space="preserve">
|
||||||
|
<value>Insert Image</value>
|
||||||
|
</data>
|
||||||
|
<data name="Message.Require.Image" xml:space="preserve">
|
||||||
|
<value>You Must Select An Image To Insert</value>
|
||||||
|
</data>
|
||||||
|
<data name="Placeholder" xml:space="preserve">
|
||||||
|
<value>Enter Your Content...</value>
|
||||||
|
</data>
|
||||||
|
<data name="SaveSettings" xml:space="preserve">
|
||||||
|
<value>Save Settings</value>
|
||||||
|
</data>
|
||||||
|
<data name="Settings" xml:space="preserve">
|
||||||
|
<value>Settings</value>
|
||||||
|
</data>
|
||||||
|
<data name="Theme.HelpText" xml:space="preserve">
|
||||||
|
<value>Specify the Rich Text Editor's theme</value>
|
||||||
|
</data>
|
||||||
|
<data name="Theme.Text" xml:space="preserve">
|
||||||
|
<value>Theme:</value>
|
||||||
|
</data>
|
||||||
|
<data name="ToolbarContent.HelpText" xml:space="preserve">
|
||||||
|
<value>Specify any toolbar content to customize the Rich Text Editor</value>
|
||||||
|
</data>
|
||||||
|
<data name="ToolbarContent.Text" xml:space="preserve">
|
||||||
|
<value>Toolbar Content:</value>
|
||||||
|
</data>
|
||||||
|
</root>
|
@ -213,6 +213,9 @@
|
|||||||
<data name="Reset" xml:space="preserve">
|
<data name="Reset" xml:space="preserve">
|
||||||
<value>Reset</value>
|
<value>Reset</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="Search Settings" xml:space="preserve">
|
||||||
|
<value>Search Settings</value>
|
||||||
|
</data>
|
||||||
<data name="Search" xml:space="preserve">
|
<data name="Search" xml:space="preserve">
|
||||||
<value>Search</value>
|
<value>Search</value>
|
||||||
</data>
|
</data>
|
||||||
@ -453,4 +456,22 @@
|
|||||||
<data name="RenderModeStatic" xml:space="preserve">
|
<data name="RenderModeStatic" xml:space="preserve">
|
||||||
<value>Static</value>
|
<value>Static</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="Disabled" xml:space="preserve">
|
||||||
|
<value>Disabled</value>
|
||||||
|
</data>
|
||||||
|
<data name="Enabled" xml:space="preserve">
|
||||||
|
<value>Enabled</value>
|
||||||
|
</data>
|
||||||
|
<data name="Module" xml:space="preserve">
|
||||||
|
<value>Module</value>
|
||||||
|
</data>
|
||||||
|
<data name="Page" xml:space="preserve">
|
||||||
|
<value>Page</value>
|
||||||
|
</data>
|
||||||
|
<data name="Site" xml:space="preserve">
|
||||||
|
<value>Site</value>
|
||||||
|
</data>
|
||||||
|
<data name="User" xml:space="preserve">
|
||||||
|
<value>User</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
@ -198,4 +198,7 @@
|
|||||||
<data name="LocationTop" xml:space="preserve">
|
<data name="LocationTop" xml:space="preserve">
|
||||||
<value>Top</value>
|
<value>Top</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="Module.CopyExisting" xml:space="preserve">
|
||||||
|
<value>Copy Existing Module</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
150
Oqtane.Client/Resources/Themes/Controls/ModuleActionsBase.resx
Normal file
150
Oqtane.Client/Resources/Themes/Controls/ModuleActionsBase.resx
Normal file
@ -0,0 +1,150 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<root>
|
||||||
|
<!--
|
||||||
|
Microsoft ResX Schema
|
||||||
|
|
||||||
|
Version 2.0
|
||||||
|
|
||||||
|
The primary goals of this format is to allow a simple XML format
|
||||||
|
that is mostly human readable. The generation and parsing of the
|
||||||
|
various data types are done through the TypeConverter classes
|
||||||
|
associated with the data types.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
... ado.net/XML headers & schema ...
|
||||||
|
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||||
|
<resheader name="version">2.0</resheader>
|
||||||
|
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||||
|
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||||
|
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||||
|
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||||
|
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||||
|
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||||
|
</data>
|
||||||
|
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||||
|
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||||
|
<comment>This is a comment</comment>
|
||||||
|
</data>
|
||||||
|
|
||||||
|
There are any number of "resheader" rows that contain simple
|
||||||
|
name/value pairs.
|
||||||
|
|
||||||
|
Each data row contains a name, and value. The row also contains a
|
||||||
|
type or mimetype. Type corresponds to a .NET class that support
|
||||||
|
text/value conversion through the TypeConverter architecture.
|
||||||
|
Classes that don't support this are serialized and stored with the
|
||||||
|
mimetype set.
|
||||||
|
|
||||||
|
The mimetype is used for serialized objects, and tells the
|
||||||
|
ResXResourceReader how to depersist the object. This is currently not
|
||||||
|
extensible. For a given mimetype the value must be set accordingly:
|
||||||
|
|
||||||
|
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||||
|
that the ResXResourceWriter will generate, however the reader can
|
||||||
|
read any of the formats listed below.
|
||||||
|
|
||||||
|
mimetype: application/x-microsoft.net.object.binary.base64
|
||||||
|
value : The object must be serialized with
|
||||||
|
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||||
|
: and then encoded with base64 encoding.
|
||||||
|
|
||||||
|
mimetype: application/x-microsoft.net.object.soap.base64
|
||||||
|
value : The object must be serialized with
|
||||||
|
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||||
|
: and then encoded with base64 encoding.
|
||||||
|
|
||||||
|
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||||
|
value : The object must be serialized into a byte array
|
||||||
|
: using a System.ComponentModel.TypeConverter
|
||||||
|
: and then encoded with base64 encoding.
|
||||||
|
-->
|
||||||
|
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||||
|
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||||
|
<xsd:element name="root" msdata:IsDataSet="true">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:choice maxOccurs="unbounded">
|
||||||
|
<xsd:element name="metadata">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||||
|
</xsd:sequence>
|
||||||
|
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||||
|
<xsd:attribute name="type" type="xsd:string" />
|
||||||
|
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||||
|
<xsd:attribute ref="xml:space" />
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
<xsd:element name="assembly">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:attribute name="alias" type="xsd:string" />
|
||||||
|
<xsd:attribute name="name" type="xsd:string" />
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
<xsd:element name="data">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||||
|
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||||
|
</xsd:sequence>
|
||||||
|
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||||
|
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||||
|
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||||
|
<xsd:attribute ref="xml:space" />
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
<xsd:element name="resheader">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||||
|
</xsd:sequence>
|
||||||
|
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
</xsd:choice>
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
</xsd:schema>
|
||||||
|
<resheader name="resmimetype">
|
||||||
|
<value>text/microsoft-resx</value>
|
||||||
|
</resheader>
|
||||||
|
<resheader name="version">
|
||||||
|
<value>2.0</value>
|
||||||
|
</resheader>
|
||||||
|
<resheader name="reader">
|
||||||
|
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||||
|
</resheader>
|
||||||
|
<resheader name="writer">
|
||||||
|
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||||
|
</resheader>
|
||||||
|
<data name="DeleteModule" xml:space="preserve">
|
||||||
|
<value>Delete Module</value>
|
||||||
|
</data>
|
||||||
|
<data name="ExportContent" xml:space="preserve">
|
||||||
|
<value>Export Content</value>
|
||||||
|
</data>
|
||||||
|
<data name="ImportContent" xml:space="preserve">
|
||||||
|
<value>Import Content</value>
|
||||||
|
</data>
|
||||||
|
<data name="ManageSettings" xml:space="preserve">
|
||||||
|
<value>Manage Settings</value>
|
||||||
|
</data>
|
||||||
|
<data name="MoveDown" xml:space="preserve">
|
||||||
|
<value>Move Down</value>
|
||||||
|
</data>
|
||||||
|
<data name="MoveToBottom" xml:space="preserve">
|
||||||
|
<value>Move To Bottom</value>
|
||||||
|
</data>
|
||||||
|
<data name="MoveToTop" xml:space="preserve">
|
||||||
|
<value>Move To Top</value>
|
||||||
|
</data>
|
||||||
|
<data name="MoveUp" xml:space="preserve">
|
||||||
|
<value>MoveUp</value>
|
||||||
|
</data>
|
||||||
|
<data name="PublishModule" xml:space="preserve">
|
||||||
|
<value>Publish Module</value>
|
||||||
|
</data>
|
||||||
|
<data name="UnpublishModule" xml:space="preserve">
|
||||||
|
<value>Unpublish Module</value>
|
||||||
|
</data>
|
||||||
|
</root>
|
@ -117,16 +117,10 @@
|
|||||||
<resheader name="writer">
|
<resheader name="writer">
|
||||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||||
</resheader>
|
</resheader>
|
||||||
<data name="InsertImage" xml:space="preserve">
|
<data name="Search" xml:space="preserve">
|
||||||
<value>Insert Image</value>
|
<value>Search</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="Close" xml:space="preserve">
|
<data name="SearchPlaceHolder" xml:space="preserve">
|
||||||
<value>Close</value>
|
<value>Search</value>
|
||||||
</data>
|
|
||||||
<data name="Message.Require.Image" xml:space="preserve">
|
|
||||||
<value>You Must Select An Image To Insert</value>
|
|
||||||
</data>
|
|
||||||
<data name="Placeholder" xml:space="preserve">
|
|
||||||
<value>Enter Your Content...</value>
|
|
||||||
</data>
|
</data>
|
||||||
</root>
|
</root>
|
@ -75,5 +75,10 @@ namespace Oqtane.Services
|
|||||||
{
|
{
|
||||||
return await GetByteArrayAsync($"{Apiurl}/download/{fileId}");
|
return await GetByteArrayAsync($"{Apiurl}/download/{fileId}");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task UnzipFileAsync(int fileId)
|
||||||
|
{
|
||||||
|
await PutAsync($"{Apiurl}/unzip/{fileId}");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -92,5 +92,13 @@ namespace Oqtane.Services
|
|||||||
/// </param>
|
/// </param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
Task<List<File>> GetFilesAsync(int siteId, string folderPath);
|
Task<List<File>> GetFilesAsync(int siteId, string folderPath);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Unzips the contents of a zip file
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="fileId">Reference to the <see cref="File"/></param>
|
||||||
|
/// </param>
|
||||||
|
/// <returns></returns>
|
||||||
|
Task UnzipFileAsync(int fileId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
13
Oqtane.Client/Services/Interfaces/ISearchResultsService.cs
Normal file
13
Oqtane.Client/Services/Interfaces/ISearchResultsService.cs
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Oqtane.Documentation;
|
||||||
|
using Oqtane.Models;
|
||||||
|
|
||||||
|
namespace Oqtane.Services
|
||||||
|
{
|
||||||
|
[PrivateApi("Mark SearchResults classes as private, since it's not very useful in the public docs")]
|
||||||
|
public interface ISearchResultsService
|
||||||
|
{
|
||||||
|
Task<SearchResults> GetSearchResultsAsync(SearchQuery searchQuery);
|
||||||
|
}
|
||||||
|
}
|
@ -179,6 +179,17 @@ namespace Oqtane.Services
|
|||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
Task UpdateSettingsAsync(Dictionary<string, string> settings, string entityName, int entityId);
|
Task UpdateSettingsAsync(Dictionary<string, string> settings, string entityName, int entityId);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Updates setting for a given entityName and Id
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="entityName"></param>
|
||||||
|
/// <param name="entityId"></param>
|
||||||
|
/// <param name="settingName"></param>
|
||||||
|
/// <param name="settingValue"></param>
|
||||||
|
/// <param name="isPrivate"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
Task AddOrUpdateSettingAsync(string entityName, int entityId, string settingName, string settingValue, bool isPrivate);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Returns a specific setting
|
/// Returns a specific setting
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -46,6 +46,14 @@ namespace Oqtane.Services
|
|||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
Task DeleteSiteAsync(int siteId);
|
Task DeleteSiteAsync(int siteId);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns a list of modules
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="siteId"></param>
|
||||||
|
/// <param name="pageId"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
Task<List<Module>> GetModulesAsync(int siteId, int pageId);
|
||||||
|
|
||||||
[PrivateApi]
|
[PrivateApi]
|
||||||
[Obsolete("This method is deprecated.", false)]
|
[Obsolete("This method is deprecated.", false)]
|
||||||
void SetAlias(Alias alias);
|
void SetAlias(Alias alias);
|
||||||
|
23
Oqtane.Client/Services/SearchResultsService.cs
Normal file
23
Oqtane.Client/Services/SearchResultsService.cs
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Net.Http;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Oqtane.Documentation;
|
||||||
|
using Oqtane.Models;
|
||||||
|
using Oqtane.Modules;
|
||||||
|
using Oqtane.Shared;
|
||||||
|
|
||||||
|
namespace Oqtane.Services
|
||||||
|
{
|
||||||
|
[PrivateApi("Don't show in the documentation, as everything should use the Interface")]
|
||||||
|
public class SearchResultsService : ServiceBase, ISearchResultsService, IClientService
|
||||||
|
{
|
||||||
|
public SearchResultsService(HttpClient http, SiteState siteState) : base(http, siteState) { }
|
||||||
|
|
||||||
|
private string ApiUrl => CreateApiUrl("SearchResults");
|
||||||
|
|
||||||
|
public async Task<SearchResults> GetSearchResultsAsync(SearchQuery searchQuery)
|
||||||
|
{
|
||||||
|
return await PostJsonAsync<SearchQuery, SearchResults>(ApiUrl, searchQuery);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -35,6 +35,7 @@ namespace Oqtane.Services
|
|||||||
if (_factory != null)
|
if (_factory != null)
|
||||||
{
|
{
|
||||||
var client = _factory.CreateClient("oqtane");
|
var client = _factory.CreateClient("oqtane");
|
||||||
|
client.BaseAddress = new Uri(_siteState.Alias.Protocol + _siteState.Alias.Name);
|
||||||
if (!client.DefaultRequestHeaders.Contains(Constants.AntiForgeryTokenHeaderName) && _siteState != null && !string.IsNullOrEmpty(_siteState.AntiForgeryToken))
|
if (!client.DefaultRequestHeaders.Contains(Constants.AntiForgeryTokenHeaderName) && _siteState != null && !string.IsNullOrEmpty(_siteState.AntiForgeryToken))
|
||||||
{
|
{
|
||||||
client.DefaultRequestHeaders.Add(Constants.AntiForgeryTokenHeaderName, _siteState.AntiForgeryToken);
|
client.DefaultRequestHeaders.Add(Constants.AntiForgeryTokenHeaderName, _siteState.AntiForgeryToken);
|
||||||
|
@ -12,7 +12,7 @@ namespace Oqtane.Services
|
|||||||
[PrivateApi("Don't show in the documentation, as everything should use the Interface")]
|
[PrivateApi("Don't show in the documentation, as everything should use the Interface")]
|
||||||
public class SettingService : ServiceBase, ISettingService
|
public class SettingService : ServiceBase, ISettingService
|
||||||
{
|
{
|
||||||
public SettingService(HttpClient http, SiteState siteState) : base(http, siteState) { }
|
public SettingService(HttpClient http, SiteState siteState) : base(http, siteState) {}
|
||||||
|
|
||||||
private string Apiurl => CreateApiUrl("Setting");
|
private string Apiurl => CreateApiUrl("Setting");
|
||||||
|
|
||||||
@ -134,7 +134,7 @@ namespace Oqtane.Services
|
|||||||
public async Task<Dictionary<string, string>> GetSettingsAsync(string entityName, int entityId)
|
public async Task<Dictionary<string, string>> GetSettingsAsync(string entityName, int entityId)
|
||||||
{
|
{
|
||||||
var dictionary = new Dictionary<string, string>();
|
var dictionary = new Dictionary<string, string>();
|
||||||
var settings = await GetJsonAsync<List<Setting>>($"{Apiurl}?entityname={entityName}&entityid={entityId}");
|
var settings = await GetSettingsAsync(entityName, entityId, "");
|
||||||
if (settings != null)
|
if (settings != null)
|
||||||
{
|
{
|
||||||
foreach (Setting setting in settings.OrderBy(item => item.SettingName).ToList())
|
foreach (Setting setting in settings.OrderBy(item => item.SettingName).ToList())
|
||||||
@ -147,7 +147,7 @@ namespace Oqtane.Services
|
|||||||
|
|
||||||
public async Task UpdateSettingsAsync(Dictionary<string, string> settings, string entityName, int entityId)
|
public async Task UpdateSettingsAsync(Dictionary<string, string> settings, string entityName, int entityId)
|
||||||
{
|
{
|
||||||
var settingsList = await GetJsonAsync<List<Setting>>($"{Apiurl}?entityname={entityName}&entityid={entityId}");
|
var settingsList = await GetSettingsAsync(entityName, entityId, "");
|
||||||
|
|
||||||
foreach (KeyValuePair<string, string> kvp in settings)
|
foreach (KeyValuePair<string, string> kvp in settings)
|
||||||
{
|
{
|
||||||
@ -192,14 +192,14 @@ namespace Oqtane.Services
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task AddOrUpdateSettingAsync(string entityName, int entityId, string settingName, string settingValue, bool isPrivate)
|
||||||
|
{
|
||||||
|
await PutAsync($"{Apiurl}/{entityName}/{entityId}/{settingName}/{settingValue}/{isPrivate}");
|
||||||
|
}
|
||||||
|
|
||||||
public async Task DeleteSettingAsync(string entityName, int entityId, string settingName)
|
public async Task DeleteSettingAsync(string entityName, int entityId, string settingName)
|
||||||
{
|
{
|
||||||
var settings = await GetJsonAsync<List<Setting>>($"{Apiurl}?entityname={entityName}&entityid={entityId}");
|
await DeleteAsync($"{Apiurl}/{entityName}/{entityId}/{settingName}");
|
||||||
var setting = settings.FirstOrDefault(item => item.SettingName == settingName);
|
|
||||||
if (setting != null)
|
|
||||||
{
|
|
||||||
await DeleteAsync($"{Apiurl}/{setting.SettingId}/{entityName}");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<List<Setting>> GetSettingsAsync(string entityName, int entityId, string settingName)
|
public async Task<List<Setting>> GetSettingsAsync(string entityName, int entityId, string settingName)
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
using Oqtane.Models;
|
using Oqtane.Models;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using System.Net.Http;
|
using System.Net.Http;
|
||||||
using System.Linq;
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using Oqtane.Shared;
|
using Oqtane.Shared;
|
||||||
using System;
|
using System;
|
||||||
@ -41,6 +40,11 @@ namespace Oqtane.Services
|
|||||||
await DeleteAsync($"{Apiurl}/{siteId}");
|
await DeleteAsync($"{Apiurl}/{siteId}");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task<List<Module>> GetModulesAsync(int siteId, int pageId)
|
||||||
|
{
|
||||||
|
return await GetJsonAsync<List<Module>>($"{Apiurl}/modules/{siteId}/{pageId}");
|
||||||
|
}
|
||||||
|
|
||||||
[Obsolete("This method is deprecated.", false)]
|
[Obsolete("This method is deprecated.", false)]
|
||||||
public void SetAlias(Alias alias)
|
public void SetAlias(Alias alias)
|
||||||
{
|
{
|
||||||
|
@ -31,7 +31,7 @@ namespace Oqtane.Services
|
|||||||
|
|
||||||
public async Task<User> GetUserAsync(string username, int siteId)
|
public async Task<User> GetUserAsync(string username, int siteId)
|
||||||
{
|
{
|
||||||
return await GetUserAsync(username, "", siteId);
|
return await GetJsonAsync<User>($"{Apiurl}/username/{username}?siteid={siteId}");
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<User> GetUserAsync(string username, string email, int siteId)
|
public async Task<User> GetUserAsync(string username, string email, int siteId)
|
||||||
|
@ -6,6 +6,7 @@ using System.Collections.Generic;
|
|||||||
using Oqtane.Documentation;
|
using Oqtane.Documentation;
|
||||||
using Oqtane.Shared;
|
using Oqtane.Shared;
|
||||||
using System;
|
using System;
|
||||||
|
using System.Globalization;
|
||||||
|
|
||||||
namespace Oqtane.Services
|
namespace Oqtane.Services
|
||||||
{
|
{
|
||||||
@ -18,7 +19,7 @@ namespace Oqtane.Services
|
|||||||
|
|
||||||
public async Task<List<Visitor>> GetVisitorsAsync(int siteId, DateTime fromDate)
|
public async Task<List<Visitor>> GetVisitorsAsync(int siteId, DateTime fromDate)
|
||||||
{
|
{
|
||||||
List<Visitor> visitors = await GetJsonAsync<List<Visitor>>($"{Apiurl}?siteid={siteId}&fromdate={fromDate.ToString("dd-MMM-yyyy")}");
|
List<Visitor> visitors = await GetJsonAsync<List<Visitor>>($"{Apiurl}?siteid={siteId}&fromdate={fromDate.ToString("yyyy-MM-dd", CultureInfo.InvariantCulture)}");
|
||||||
return visitors.OrderByDescending(item => item.VisitedOn).ToList();
|
return visitors.OrderByDescending(item => item.VisitedOn).ToList();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
@namespace Oqtane.Themes
|
@namespace Oqtane.Themes
|
||||||
@inherits ContainerBase
|
@inherits ContainerBase
|
||||||
@inject NavigationManager NavigationManager
|
|
||||||
|
|
||||||
<div class="app-admin-modal">
|
<div class="app-admin-modal">
|
||||||
<div class="modal" tabindex="-1" role="dialog">
|
<div class="modal" tabindex="-1" role="dialog">
|
||||||
@ -8,10 +7,7 @@
|
|||||||
<div class="modal-content">
|
<div class="modal-content">
|
||||||
<div class="modal-header">
|
<div class="modal-header">
|
||||||
<h5 class="modal-title"><ModuleTitle /></h5>
|
<h5 class="modal-title"><ModuleTitle /></h5>
|
||||||
<form method="post" class="app-form-inline" @formname="AdminContainerForm" @onsubmit="@CloseModal" data-enhance>
|
<a href="@_url" class="btn-close" aria-label="Close"></a>
|
||||||
<input type="hidden" name="@Constants.RequestVerificationToken" value="@SiteState.AntiForgeryToken" />
|
|
||||||
<button type="submit" class="btn-close" aria-label="Close"></button>
|
|
||||||
</form>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-body">
|
<div class="modal-body">
|
||||||
<ModuleInstance />
|
<ModuleInstance />
|
||||||
@ -22,9 +18,11 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
@code {
|
@code {
|
||||||
private void CloseModal()
|
private string _url;
|
||||||
|
|
||||||
|
protected override void OnParametersSet()
|
||||||
{
|
{
|
||||||
NavigationManager.NavigateTo((!string.IsNullOrEmpty(PageState.ReturnUrl)) ? PageState.ReturnUrl : NavigateUrl());
|
_url = (!string.IsNullOrEmpty(PageState.ReturnUrl)) ? PageState.ReturnUrl : NavigateUrl();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -9,13 +9,19 @@
|
|||||||
<div class="row flex-xl-nowrap gx-0">
|
<div class="row flex-xl-nowrap gx-0">
|
||||||
<div class="sidebar">
|
<div class="sidebar">
|
||||||
<nav class="navbar">
|
<nav class="navbar">
|
||||||
<Logo /><Menu Orientation="Vertical" />
|
<Logo />
|
||||||
|
<Menu Orientation="Vertical" />
|
||||||
</nav>
|
</nav>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="main g-0">
|
<div class="main g-0">
|
||||||
<div class="top-row px-4">
|
<div class="top-row px-4">
|
||||||
<div class="ms-auto"><UserProfile /> <Login /> <ControlPanel LanguageDropdownAlignment="right" /></div>
|
<div class="ms-auto">
|
||||||
|
<Search CssClass="me-3 text-center d-inline-block" />
|
||||||
|
<UserProfile />
|
||||||
|
<Login />
|
||||||
|
<ControlPanel LanguageDropdownAlignment="right" />
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="row px-4">
|
<div class="row px-4">
|
||||||
@ -31,9 +37,13 @@
|
|||||||
public override List<Resource> Resources => new List<Resource>()
|
public override List<Resource> Resources => new List<Resource>()
|
||||||
{
|
{
|
||||||
// obtained from https://cdnjs.com/libraries
|
// obtained from https://cdnjs.com/libraries
|
||||||
new Resource { ResourceType = ResourceType.Stylesheet, Url = "https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.3.2/css/bootstrap.min.css", Integrity = "sha512-b2QcS5SsA8tZodcDtGRELiGv5SaKSk1vDHDaQRda0htPYWZ6046lr3kJ5bAAQdpV2mmA/4v0wQF9MyU6/pDIAg==", CrossOrigin = "anonymous" },
|
new Resource { ResourceType = ResourceType.Stylesheet, Url = "https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.3.3/css/bootstrap.min.css",
|
||||||
|
Integrity = "sha512-jnSuA4Ss2PkkikSOLtYs8BlYIeeIK1h99ty4YfvRPAlzr377vr3CXDb7sb7eEEBYjDtcYj+AjBH3FLv5uSJuXg==",
|
||||||
|
CrossOrigin = "anonymous" },
|
||||||
new Resource { ResourceType = ResourceType.Stylesheet, Url = ThemePath() + "Theme.css" },
|
new Resource { ResourceType = ResourceType.Stylesheet, Url = ThemePath() + "Theme.css" },
|
||||||
new Resource { ResourceType = ResourceType.Script, Url = "https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.3.2/js/bootstrap.bundle.min.js", Integrity = "sha512-X/YkDZyjTf4wyc2Vy16YGCPHwAY8rZJY+POgokZjQB2mhIRFJCckEGc6YyX9eNsPfn0PzThEuNs+uaomE5CO6A==", CrossOrigin = "anonymous", Location = ResourceLocation.Body }
|
new Resource { ResourceType = ResourceType.Script, Url = "https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.3.3/js/bootstrap.bundle.min.js",
|
||||||
|
Integrity = "sha512-7Pi/otdlbbCR+LnW+F7PwFcSDJOuUJB3OxtEHbg4vSMvzvJjde4Po1v4BR9Gdc9aXNUNFVUY+SK51wWT8WF0Gg==",
|
||||||
|
CrossOrigin = "anonymous", Location = ResourceLocation.Body },
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -6,10 +6,26 @@
|
|||||||
{
|
{
|
||||||
@if (PageState.RenderMode == RenderModes.Interactive)
|
@if (PageState.RenderMode == RenderModes.Interactive)
|
||||||
{
|
{
|
||||||
<ModuleActionsInteractive PageState="@PageState" ModuleState="@ModuleState" />
|
<ModuleActionsInteractive PageState="@_pageState" ModuleState="@ModuleState" />
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
<ModuleActionsInteractive PageState="@PageState" ModuleState="@ModuleState" @rendermode="@InteractiveRenderMode.GetInteractiveRenderMode(PageState.Site.Runtime, PageState.Site.Prerender)" />
|
<ModuleActionsInteractive PageState="@_pageState" ModuleState="@ModuleState" @rendermode="@InteractiveRenderMode.GetInteractiveRenderMode(PageState.Site.Runtime, false)" />
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@code {
|
||||||
|
private PageState _pageState;
|
||||||
|
|
||||||
|
protected override void OnParametersSet()
|
||||||
|
{
|
||||||
|
// trim PageState to mitigate page bloat caused by Blazor serializing/encrypting state when crossing render mode boundaries
|
||||||
|
_pageState = new PageState
|
||||||
|
{
|
||||||
|
Alias = PageState.Alias,
|
||||||
|
Page = PageState.Page,
|
||||||
|
User = PageState.User,
|
||||||
|
EditMode = PageState.EditMode
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,8 +7,9 @@ using Oqtane.Models;
|
|||||||
using Oqtane.Security;
|
using Oqtane.Security;
|
||||||
using Oqtane.Services;
|
using Oqtane.Services;
|
||||||
using Oqtane.Shared;
|
using Oqtane.Shared;
|
||||||
using Oqtane.UI;
|
|
||||||
using System.Net;
|
using System.Net;
|
||||||
|
using Microsoft.Extensions.Localization;
|
||||||
|
using Oqtane.UI;
|
||||||
|
|
||||||
// ReSharper disable UnassignedGetOnlyAutoProperty
|
// ReSharper disable UnassignedGetOnlyAutoProperty
|
||||||
// ReSharper disable MemberCanBePrivate.Global
|
// ReSharper disable MemberCanBePrivate.Global
|
||||||
@ -20,6 +21,7 @@ namespace Oqtane.Themes.Controls
|
|||||||
[Inject] public NavigationManager NavigationManager { get; set; }
|
[Inject] public NavigationManager NavigationManager { get; set; }
|
||||||
[Inject] public IPageModuleService PageModuleService { get; set; }
|
[Inject] public IPageModuleService PageModuleService { get; set; }
|
||||||
[Inject] public IModuleService ModuleService { get; set; }
|
[Inject] public IModuleService ModuleService { get; set; }
|
||||||
|
[Inject] public IStringLocalizer<ModuleActionsBase> Localizer { get; set; }
|
||||||
|
|
||||||
[Parameter] public PageState PageState { get; set; }
|
[Parameter] public PageState PageState { get; set; }
|
||||||
[Parameter] public Module ModuleState { get; set; }
|
[Parameter] public Module ModuleState { get; set; }
|
||||||
@ -37,30 +39,30 @@ namespace Oqtane.Themes.Controls
|
|||||||
|
|
||||||
if (PageState.EditMode && UserSecurity.IsAuthorized(PageState.User, PermissionNames.Edit, PageState.Page.PermissionList))
|
if (PageState.EditMode && UserSecurity.IsAuthorized(PageState.User, PermissionNames.Edit, PageState.Page.PermissionList))
|
||||||
{
|
{
|
||||||
actionList.Add(new ActionViewModel { Icon = Icons.Cog, Name = "Manage Settings", Action = async (u, m) => await Settings(u, m) });
|
actionList.Add(new ActionViewModel { Icon = Icons.Cog, Name = Localizer["ManageSettings"], Action = async (u, m) => await Settings(u, m) });
|
||||||
|
|
||||||
if (UserSecurity.ContainsRole(ModuleState.PermissionList, PermissionNames.View, RoleNames.Everyone))
|
if (UserSecurity.ContainsRole(ModuleState.PermissionList, PermissionNames.View, RoleNames.Everyone))
|
||||||
{
|
{
|
||||||
actionList.Add(new ActionViewModel { Icon = Icons.CircleX, Name = "Unpublish Module", Action = async (s, m) => await Unpublish(s, m) });
|
actionList.Add(new ActionViewModel { Icon = Icons.CircleX, Name = Localizer["UnpublishModule"], Action = async (s, m) => await Unpublish(s, m) });
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
actionList.Add(new ActionViewModel { Icon = Icons.CircleCheck, Name = "Publish Module", Action = async (s, m) => await Publish(s, m) });
|
actionList.Add(new ActionViewModel { Icon = Icons.CircleCheck, Name = Localizer["PublishModule"], Action = async (s, m) => await Publish(s, m) });
|
||||||
}
|
}
|
||||||
actionList.Add(new ActionViewModel { Icon = Icons.Trash, Name = "Delete Module", Action = async (u, m) => await DeleteModule(u, m) });
|
actionList.Add(new ActionViewModel { Icon = Icons.Trash, Name = Localizer["DeleteModule"], Action = async (u, m) => await DeleteModule(u, m) });
|
||||||
|
|
||||||
if (ModuleState.ModuleDefinition != null && ModuleState.ModuleDefinition.IsPortable)
|
if (ModuleState.ModuleDefinition != null && ModuleState.ModuleDefinition.IsPortable)
|
||||||
{
|
{
|
||||||
actionList.Add(new ActionViewModel { Name = "" });
|
actionList.Add(new ActionViewModel { Name = "" });
|
||||||
actionList.Add(new ActionViewModel { Icon = Icons.CloudUpload, Name = "Import Content", Action = async (u, m) => await EditUrlAsync(u, m.ModuleId, "Import") });
|
actionList.Add(new ActionViewModel { Icon = Icons.CloudUpload, Name = Localizer["ImportContent"], Action = async (u, m) => await EditUrlAsync(u, m.ModuleId, "Import") });
|
||||||
actionList.Add(new ActionViewModel { Icon = Icons.CloudDownload, Name = "Export Content", Action = async (u, m) => await EditUrlAsync(u, m.ModuleId, "Export") });
|
actionList.Add(new ActionViewModel { Icon = Icons.CloudDownload, Name = Localizer["ExportContent"], Action = async (u, m) => await EditUrlAsync(u, m.ModuleId, "Export") });
|
||||||
}
|
}
|
||||||
|
|
||||||
actionList.Add(new ActionViewModel { Name = "" });
|
actionList.Add(new ActionViewModel { Name = "" });
|
||||||
|
|
||||||
if (ModuleState.PaneModuleIndex > 0)
|
if (ModuleState.PaneModuleIndex > 0)
|
||||||
{
|
{
|
||||||
actionList.Add(new ActionViewModel { Icon = Icons.DataTransferUpload, Name = "Move To Top", Action = async (s, m) => await MoveTop(s, m) });
|
actionList.Add(new ActionViewModel { Icon = Icons.DataTransferUpload, Name = Localizer["MoveToTop"], Action = async (s, m) => await MoveTop(s, m) });
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ModuleState.PaneModuleIndex > 0)
|
if (ModuleState.PaneModuleIndex > 0)
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
|
|
||||||
@if (ShowLanguageSwitcher)
|
@if (ShowLanguageSwitcher)
|
||||||
{
|
{
|
||||||
<LanguageSwitcher DropdownAlignment="@LanguageDropdownAlignment" />
|
<LanguageSwitcher ButtonClass="@ButtonClass" DropdownAlignment="@LanguageDropdownAlignment" />
|
||||||
}
|
}
|
||||||
|
|
||||||
@if (_showEditMode || (PageState.Page.IsPersonalizable && PageState.User != null && UserSecurity.IsAuthorized(PageState.User, RoleNames.Registered)))
|
@if (_showEditMode || (PageState.Page.IsPersonalizable && PageState.User != null && UserSecurity.IsAuthorized(PageState.User, RoleNames.Registered)))
|
||||||
@ -32,11 +32,11 @@
|
|||||||
{
|
{
|
||||||
@if (PageState.RenderMode == RenderModes.Interactive)
|
@if (PageState.RenderMode == RenderModes.Interactive)
|
||||||
{
|
{
|
||||||
<ControlPanelInteractive PageState="@PageState" SiteState="@SiteState" ButtonClass="@ButtonClass" ContainerClass="@ContainerClass" HeaderClass="@HeaderClass" BodyClass="@BodyClass" ShowLanguageSwitcher="@ShowLanguageSwitcher" LanguageDropdownAlignment="@LanguageDropdownAlignment" />
|
<ControlPanelInteractive PageState="@_pageState" SiteState="@SiteState" ButtonClass="@ButtonClass" ContainerClass="@ContainerClass" HeaderClass="@HeaderClass" BodyClass="@BodyClass" ShowLanguageSwitcher="@ShowLanguageSwitcher" LanguageDropdownAlignment="@LanguageDropdownAlignment" CanViewAdminDashboard="@_canViewAdminDashboard" />
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
<ControlPanelInteractive PageState="@PageState" SiteState="@SiteState" ButtonClass="@ButtonClass" ContainerClass="@ContainerClass" HeaderClass="@HeaderClass" BodyClass="@BodyClass" ShowLanguageSwitcher="@ShowLanguageSwitcher" LanguageDropdownAlignment="@LanguageDropdownAlignment" @rendermode="@InteractiveRenderMode.GetInteractiveRenderMode(PageState.Site.Runtime, PageState.Site.Prerender)" />
|
<ControlPanelInteractive PageState="@_pageState" SiteState="@SiteState" ButtonClass="@ButtonClass" ContainerClass="@ContainerClass" HeaderClass="@HeaderClass" BodyClass="@BodyClass" ShowLanguageSwitcher="@ShowLanguageSwitcher" LanguageDropdownAlignment="@LanguageDropdownAlignment" CanViewAdminDashboard="@_canViewAdminDashboard" @rendermode="@InteractiveRenderMode.GetInteractiveRenderMode(PageState.Site.Runtime, false)" />
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -59,6 +59,7 @@
|
|||||||
[Parameter]
|
[Parameter]
|
||||||
public string LanguageDropdownAlignment { get; set; } = string.Empty; // Empty or Left or Right
|
public string LanguageDropdownAlignment { get; set; } = string.Empty; // Empty or Left or Right
|
||||||
|
|
||||||
|
private PageState _pageState;
|
||||||
private bool _canViewAdminDashboard = false;
|
private bool _canViewAdminDashboard = false;
|
||||||
private bool _showEditMode = false;
|
private bool _showEditMode = false;
|
||||||
|
|
||||||
@ -73,7 +74,7 @@
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
foreach (var module in PageState.Modules.Where(item => item.PageId == PageState.Page.PageId))
|
foreach (var module in PageState.Modules)
|
||||||
{
|
{
|
||||||
if (UserSecurity.IsAuthorized(PageState.User, PermissionNames.Edit, module.PermissionList))
|
if (UserSecurity.IsAuthorized(PageState.User, PermissionNames.Edit, module.PermissionList))
|
||||||
{
|
{
|
||||||
@ -82,6 +83,24 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// trim PageState to mitigate page bloat caused by Blazor serializing/encrypting state when crossing render mode boundaries
|
||||||
|
_pageState = new PageState
|
||||||
|
{
|
||||||
|
Alias = PageState.Alias,
|
||||||
|
Site = new Site
|
||||||
|
{
|
||||||
|
DefaultContainerType = PageState.Site.DefaultContainerType,
|
||||||
|
Settings = PageState.Site.Settings,
|
||||||
|
Themes = PageState.Site.Themes
|
||||||
|
},
|
||||||
|
Page = PageState.Page,
|
||||||
|
User = PageState.User,
|
||||||
|
Uri = PageState.Uri,
|
||||||
|
Route = PageState.Route,
|
||||||
|
RenderMode = PageState.RenderMode,
|
||||||
|
Runtime = PageState.Runtime
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool CanViewAdminDashboard()
|
private bool CanViewAdminDashboard()
|
||||||
@ -115,8 +134,7 @@
|
|||||||
if (PageState.User != null)
|
if (PageState.User != null)
|
||||||
{
|
{
|
||||||
// preserve edit mode for authenticated users
|
// preserve edit mode for authenticated users
|
||||||
var userSettings = new Dictionary<string, string> { { "CP-editmode", (PageState.EditMode) ? PageState.Page.PageId.ToString() : "-1" } };
|
await SettingService.AddOrUpdateSettingAsync(EntityNames.User, PageState.User.UserId, "CP-editmode", (PageState.EditMode) ? PageState.Page.PageId.ToString() : "-1", false);
|
||||||
await SettingService.UpdateUserSettingsAsync(userSettings, PageState.User.UserId);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// preserve other querystring parameters
|
// preserve other querystring parameters
|
||||||
|
@ -15,6 +15,7 @@
|
|||||||
@inject ILogService LoggingService
|
@inject ILogService LoggingService
|
||||||
@inject IStringLocalizer<ControlPanelInteractive> Localizer
|
@inject IStringLocalizer<ControlPanelInteractive> Localizer
|
||||||
@inject IStringLocalizer<SharedResources> SharedLocalizer
|
@inject IStringLocalizer<SharedResources> SharedLocalizer
|
||||||
|
@inject IServiceProvider ServiceProvider
|
||||||
|
|
||||||
<button type="button" class="btn @ButtonClass ms-1" data-bs-toggle="offcanvas" data-bs-target="#offcanvasControlPanel" aria-controls="offcanvasControlPanel" @onclick="ClearMessage">
|
<button type="button" class="btn @ButtonClass ms-1" data-bs-toggle="offcanvas" data-bs-target="#offcanvasControlPanel" aria-controls="offcanvasControlPanel" @onclick="ClearMessage">
|
||||||
<span class="oi oi-cog"></span>
|
<span class="oi oi-cog"></span>
|
||||||
@ -27,7 +28,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="@BodyClass">
|
<div class="@BodyClass">
|
||||||
<div class="container-fluid">
|
<div class="container-fluid">
|
||||||
@if (_canViewAdminDashboard)
|
@if (CanViewAdminDashboard)
|
||||||
{
|
{
|
||||||
<div class="row d-flex">
|
<div class="row d-flex">
|
||||||
<div class="col">
|
<div class="col">
|
||||||
@ -93,9 +94,13 @@
|
|||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col text-center">
|
<div class="col text-center">
|
||||||
<label for="Module" class="control-label">@Localizer["Module.Manage"]</label>
|
<label for="Module" class="control-label">@Localizer["Module.Manage"]</label>
|
||||||
<select class="form-select" @bind="@_moduleType">
|
<select class="form-select" @onchange="(e => ModuleTypeChanged(e))">
|
||||||
<option value="new">@Localizer["Module.AddNew"]</option>
|
<option value="new">@Localizer["Module.AddNew"]</option>
|
||||||
<option value="existing">@Localizer["Module.AddExisting"]</option>
|
@if (PageState.Page.UserId == null)
|
||||||
|
{
|
||||||
|
<option value="add">@Localizer["Module.AddExisting"]</option>
|
||||||
|
<option value="copy">@Localizer["Module.CopyExisting"]</option>
|
||||||
|
}
|
||||||
</select>
|
</select>
|
||||||
@if (_moduleType == "new")
|
@if (_moduleType == "new")
|
||||||
{
|
{
|
||||||
@ -138,7 +143,7 @@
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
<select class="form-select mt-1" @onchange="(e => PageChanged(e))">
|
<select class="form-select mt-1" value="@_pageId" @onchange="(e => PageChanged(e))">
|
||||||
<option value="-"><@Localizer["Page.Select"]></option>
|
<option value="-"><@Localizer["Page.Select"]></option>
|
||||||
@foreach (Page p in _pages)
|
@foreach (Page p in _pages)
|
||||||
{
|
{
|
||||||
@ -211,7 +216,7 @@
|
|||||||
|
|
||||||
<div class="row d-flex">
|
<div class="row d-flex">
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<button type="button" data-bs-dismiss="offcanvas" class="btn btn-secondary col-12" @onclick=@(async () => await LogoutUser())>@Localizer["Logout"]</button>
|
<button type="button" data-bs-dismiss="offcanvas" class="btn btn-secondary col-12 mt-2" @onclick=@(async () => await LogoutUser())>@Localizer["Logout"]</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -243,7 +248,9 @@
|
|||||||
[Parameter]
|
[Parameter]
|
||||||
public string LanguageDropdownAlignment { get; set; }
|
public string LanguageDropdownAlignment { get; set; }
|
||||||
|
|
||||||
private bool _canViewAdminDashboard = false;
|
[Parameter]
|
||||||
|
public bool CanViewAdminDashboard { get; set; }
|
||||||
|
|
||||||
private bool _deleteConfirmation = false;
|
private bool _deleteConfirmation = false;
|
||||||
private List<string> _categories = new List<string>();
|
private List<string> _categories = new List<string>();
|
||||||
private List<ModuleDefinition> _allModuleDefinitions;
|
private List<ModuleDefinition> _allModuleDefinitions;
|
||||||
@ -273,44 +280,17 @@
|
|||||||
// repopulate the SiteState service based on the values passed in the SiteState parameter (this is how state is marshalled across the render mode boundary)
|
// repopulate the SiteState service based on the values passed in the SiteState parameter (this is how state is marshalled across the render mode boundary)
|
||||||
ComponentSiteState.Hydrate(SiteState);
|
ComponentSiteState.Hydrate(SiteState);
|
||||||
|
|
||||||
_canViewAdminDashboard = CanViewAdminDashboard();
|
|
||||||
if (UserSecurity.IsAuthorized(PageState.User, PermissionNames.Edit, PageState.Page.PermissionList))
|
if (UserSecurity.IsAuthorized(PageState.User, PermissionNames.Edit, PageState.Page.PermissionList))
|
||||||
{
|
{
|
||||||
LoadSettingsAsync();
|
LoadSettingsAsync();
|
||||||
|
|
||||||
_pages?.Clear();
|
|
||||||
foreach (Page p in PageState.Pages)
|
|
||||||
{
|
|
||||||
if (UserSecurity.IsAuthorized(PageState.User, PermissionNames.View, p.PermissionList))
|
|
||||||
{
|
|
||||||
_pages.Add(p);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
_containers = ThemeService.GetContainerControls(PageState.Site.Themes, PageState.Page.ThemeType);
|
_containers = ThemeService.GetContainerControls(PageState.Site.Themes, PageState.Page.ThemeType);
|
||||||
_containerType = PageState.Site.DefaultContainerType;
|
_containerType = PageState.Site.DefaultContainerType;
|
||||||
_allModuleDefinitions = await ModuleDefinitionService.GetModuleDefinitionsAsync(PageState.Site.SiteId);
|
_allModuleDefinitions = await ModuleDefinitionService.GetModuleDefinitionsAsync(PageState.Page.SiteId);
|
||||||
_moduleDefinitions = _allModuleDefinitions.Where(item => item.Categories.Contains(_category)).ToList();
|
_moduleDefinitions = _allModuleDefinitions.Where(item => item.Categories.Contains(_category)).ToList();
|
||||||
_categories = _allModuleDefinitions.SelectMany(m => m.Categories.Split(',')).Distinct().ToList();
|
_categories = _allModuleDefinitions.SelectMany(m => m.Categories.Split(',', StringSplitOptions.RemoveEmptyEntries)).Distinct().Where(item => item != "Headless").ToList();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool CanViewAdminDashboard()
|
|
||||||
{
|
|
||||||
var admin = PageState.Pages.FirstOrDefault(item => item.Path == "admin");
|
|
||||||
if (admin != null)
|
|
||||||
{
|
|
||||||
foreach (var page in PageState.Pages.Where(item => item.ParentId == admin?.PageId))
|
|
||||||
{
|
|
||||||
if (UserSecurity.IsAuthorized(PageState.User, PermissionNames.View, page.PermissionList))
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void CategoryChanged(ChangeEventArgs e)
|
private void CategoryChanged(ChangeEventArgs e)
|
||||||
{
|
{
|
||||||
_category = (string)e.Value;
|
_category = (string)e.Value;
|
||||||
@ -334,14 +314,26 @@
|
|||||||
StateHasChanged();
|
StateHasChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void PageChanged(ChangeEventArgs e)
|
private async Task ModuleTypeChanged(ChangeEventArgs e)
|
||||||
|
{
|
||||||
|
_moduleType = (string)e.Value;
|
||||||
|
if (_moduleType != "new")
|
||||||
|
{
|
||||||
|
_pages = await PageService.GetPagesAsync(PageState.Page.SiteId);
|
||||||
|
}
|
||||||
|
_pageId = "-";
|
||||||
|
_moduleId = "-";
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task PageChanged(ChangeEventArgs e)
|
||||||
{
|
{
|
||||||
_pageId = (string)e.Value;
|
_pageId = (string)e.Value;
|
||||||
if (_pageId != "-")
|
if (_pageId != "-")
|
||||||
{
|
{
|
||||||
_modules = PageState.Modules
|
_modules = await ModuleService.GetModulesAsync(PageState.Page.SiteId);
|
||||||
.Where(module => module.PageId == int.Parse(_pageId) &&
|
_modules = _modules.Where(module => module.PageId == int.Parse(_pageId) &&
|
||||||
UserSecurity.IsAuthorized(PageState.User, PermissionNames.View, module.PermissionList))
|
UserSecurity.IsAuthorized(PageState.User, PermissionNames.View, module.PermissionList) &&
|
||||||
|
(_moduleType == "add" || module.ModuleDefinition.IsPortable))
|
||||||
.ToList();
|
.ToList();
|
||||||
}
|
}
|
||||||
_moduleId = "-";
|
_moduleId = "-";
|
||||||
@ -354,40 +346,45 @@
|
|||||||
{
|
{
|
||||||
if ((_moduleType == "new" && _moduleDefinitionName != "-") || (_moduleType != "new" && _moduleId != "-"))
|
if ((_moduleType == "new" && _moduleDefinitionName != "-") || (_moduleType != "new" && _moduleId != "-"))
|
||||||
{
|
{
|
||||||
|
var newModuleId = _moduleId != "-" ? int.Parse(_moduleId) : 0;
|
||||||
if (_moduleType == "new")
|
if (_moduleType == "new")
|
||||||
{
|
{
|
||||||
Module module = new Module();
|
Module module = new Module();
|
||||||
module.SiteId = PageState.Site.SiteId;
|
module.SiteId = PageState.Page.SiteId;
|
||||||
module.PageId = PageState.Page.PageId;
|
module.PageId = PageState.Page.PageId;
|
||||||
module.ModuleDefinitionName = _moduleDefinitionName;
|
module.ModuleDefinitionName = _moduleDefinitionName;
|
||||||
module.AllPages = false;
|
module.AllPages = false;
|
||||||
|
module.PermissionList = GenerateDefaultPermissions(module.SiteId);
|
||||||
var permissions = new List<Permission>();
|
|
||||||
if (_visibility == "view")
|
|
||||||
{
|
|
||||||
// set module view permissions to page view permissions
|
|
||||||
permissions = SetPermissions(permissions, module.SiteId, PermissionNames.View, PermissionNames.View);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// set module view permissions to page edit permissions
|
|
||||||
permissions = SetPermissions(permissions, module.SiteId, PermissionNames.View, PermissionNames.Edit);
|
|
||||||
}
|
|
||||||
// set module edit permissions to page edit permissions
|
|
||||||
permissions = SetPermissions(permissions, module.SiteId, PermissionNames.Edit, PermissionNames.Edit);
|
|
||||||
module.PermissionList = permissions;
|
|
||||||
|
|
||||||
module = await ModuleService.AddModuleAsync(module);
|
module = await ModuleService.AddModuleAsync(module);
|
||||||
_moduleId = module.ModuleId.ToString();
|
newModuleId = module.ModuleId;
|
||||||
|
}
|
||||||
|
else if (_moduleType == "copy")
|
||||||
|
{
|
||||||
|
var module = await ModuleService.GetModuleAsync(int.Parse(_moduleId));
|
||||||
|
module.ModuleId = 0;
|
||||||
|
module.SiteId = PageState.Page.SiteId;
|
||||||
|
module.PageId = PageState.Page.PageId;
|
||||||
|
module.AllPages = false;
|
||||||
|
module.PermissionList = GenerateDefaultPermissions(module.SiteId);
|
||||||
|
|
||||||
|
module = await ModuleService.AddModuleAsync(module);
|
||||||
|
var moduleContent = await ModuleService.ExportModuleAsync(int.Parse(_moduleId), PageState.Page.PageId);
|
||||||
|
if (!string.IsNullOrEmpty(moduleContent))
|
||||||
|
{
|
||||||
|
await ModuleService.ImportModuleAsync(module.ModuleId, PageState.Page.PageId, moduleContent);
|
||||||
|
}
|
||||||
|
|
||||||
|
newModuleId = module.ModuleId;
|
||||||
}
|
}
|
||||||
|
|
||||||
var pageModule = new PageModule
|
var pageModule = new PageModule
|
||||||
{
|
{
|
||||||
PageId = PageState.Page.PageId,
|
PageId = PageState.Page.PageId,
|
||||||
ModuleId = int.Parse(_moduleId),
|
ModuleId = newModuleId,
|
||||||
Title = _title
|
Title = _title
|
||||||
};
|
};
|
||||||
if (pageModule.Title == "")
|
if (string.IsNullOrEmpty(pageModule.Title))
|
||||||
{
|
{
|
||||||
if (_moduleType == "new")
|
if (_moduleType == "new")
|
||||||
{
|
{
|
||||||
@ -412,10 +409,17 @@
|
|||||||
await PageModuleService.UpdatePageModuleOrderAsync(pageModule.PageId, pageModule.Pane);
|
await PageModuleService.UpdatePageModuleOrderAsync(pageModule.PageId, pageModule.Pane);
|
||||||
await UpdateSettingsAsync();
|
await UpdateSettingsAsync();
|
||||||
|
|
||||||
|
if (PageState.RenderMode == RenderModes.Interactive)
|
||||||
|
{
|
||||||
_message = $"<div class=\"alert alert-success mt-2 text-center\" role=\"alert\">{Localizer["Success.Page.ModuleAdd"]}</div>";
|
_message = $"<div class=\"alert alert-success mt-2 text-center\" role=\"alert\">{Localizer["Success.Page.ModuleAdd"]}</div>";
|
||||||
_title = "";
|
_title = "";
|
||||||
NavigationManager.NavigateTo(Utilities.NavigateUrl(PageState.Alias.Path, PageState.Page.Path, ""));
|
NavigationManager.NavigateTo(Utilities.NavigateUrl(PageState.Alias.Path, PageState.Page.Path, ""));
|
||||||
}
|
}
|
||||||
|
else // reload page in static rendering
|
||||||
|
{
|
||||||
|
NavigationManager.NavigateTo(Utilities.NavigateUrl(PageState.Alias.Path, PageState.Page.Path, ""), true);
|
||||||
|
}
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
_message = $"<div class=\"alert alert-warning mt-2 text-center\" role=\"alert\">{Localizer["Message.Require.ModuleSelect"]}</div>";
|
_message = $"<div class=\"alert alert-warning mt-2 text-center\" role=\"alert\">{Localizer["Message.Require.ModuleSelect"]}</div>";
|
||||||
@ -427,6 +431,25 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private List<Permission> GenerateDefaultPermissions(int siteId)
|
||||||
|
{
|
||||||
|
var permissions = new List<Permission>();
|
||||||
|
if (_visibility == "view")
|
||||||
|
{
|
||||||
|
// set module view permissions to page view permissions
|
||||||
|
permissions = SetPermissions(permissions, siteId, PermissionNames.View, PermissionNames.View);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// set module view permissions to page edit permissions
|
||||||
|
permissions = SetPermissions(permissions, siteId, PermissionNames.View, PermissionNames.Edit);
|
||||||
|
}
|
||||||
|
// set module edit permissions to page edit permissions
|
||||||
|
permissions = SetPermissions(permissions, siteId, PermissionNames.Edit, PermissionNames.Edit);
|
||||||
|
|
||||||
|
return permissions;
|
||||||
|
}
|
||||||
|
|
||||||
private List<Permission> SetPermissions(List<Permission> permissions, int siteId, string modulePermission, string pagePermission)
|
private List<Permission> SetPermissions(List<Permission> permissions, int siteId, string modulePermission, string pagePermission)
|
||||||
{
|
{
|
||||||
foreach (var permission in PageState.Page.PermissionList.Where(item => item.PermissionName == pagePermission))
|
foreach (var permission in PageState.Page.PermissionList.Where(item => item.PermissionName == pagePermission))
|
||||||
@ -438,27 +461,19 @@
|
|||||||
|
|
||||||
private void Navigate(string location)
|
private void Navigate(string location)
|
||||||
{
|
{
|
||||||
Module module;
|
int moduleId;
|
||||||
switch (location)
|
switch (location)
|
||||||
{
|
{
|
||||||
case "Admin":
|
case "Admin":
|
||||||
// get admin dashboard moduleid
|
// get admin dashboard moduleid
|
||||||
module = PageState.Modules.FirstOrDefault(item => item.ModuleDefinitionName == Constants.AdminDashboardModule);
|
moduleId = int.Parse(PageState.Site.Settings[Constants.AdminDashboardModule]);
|
||||||
if (module != null)
|
NavigationManager.NavigateTo(Utilities.EditUrl(PageState.Alias.Path, "admin", moduleId, "Index", "returnurl=" + WebUtility.UrlEncode(PageState.Route.PathAndQuery)));
|
||||||
{
|
|
||||||
NavigationManager.NavigateTo(Utilities.EditUrl(PageState.Alias.Path, "admin", module.ModuleId, "Index", "returnurl=" + WebUtility.UrlEncode(PageState.Route.PathAndQuery)));
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
case "Add":
|
case "Add":
|
||||||
case "Edit":
|
case "Edit":
|
||||||
string url = "";
|
|
||||||
// get page management moduleid
|
// get page management moduleid
|
||||||
module = PageState.Modules.FirstOrDefault(item => item.ModuleDefinitionName == Constants.PageManagementModule);
|
moduleId = int.Parse(PageState.Site.Settings[Constants.PageManagementModule]);
|
||||||
if (module != null)
|
NavigationManager.NavigateTo(Utilities.EditUrl(PageState.Alias.Path, "admin/pages", moduleId, location, $"id={PageState.Page.PageId}&returnurl={WebUtility.UrlEncode(PageState.Route.PathAndQuery)}"));
|
||||||
{
|
|
||||||
url = Utilities.EditUrl(PageState.Alias.Path, "admin/pages", module.ModuleId, location, $"id={PageState.Page.PageId}&returnurl={WebUtility.UrlEncode(PageState.Route.PathAndQuery)}");
|
|
||||||
NavigationManager.NavigateTo(url);
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -473,11 +488,11 @@
|
|||||||
case "publish":
|
case "publish":
|
||||||
if (!permissions.Any(item => item.PermissionName == PermissionNames.View && item.RoleName == RoleNames.Everyone))
|
if (!permissions.Any(item => item.PermissionName == PermissionNames.View && item.RoleName == RoleNames.Everyone))
|
||||||
{
|
{
|
||||||
permissions.Add(new Permission(PageState.Site.SiteId, EntityNames.Page, PageState.Page.PageId, PermissionNames.View, RoleNames.Everyone, null, true));
|
permissions.Add(new Permission(PageState.Page.SiteId, EntityNames.Page, PageState.Page.PageId, PermissionNames.View, RoleNames.Everyone, null, true));
|
||||||
}
|
}
|
||||||
if (!permissions.Any(item => item.PermissionName == PermissionNames.View && item.RoleName == RoleNames.Registered))
|
if (!permissions.Any(item => item.PermissionName == PermissionNames.View && item.RoleName == RoleNames.Registered))
|
||||||
{
|
{
|
||||||
permissions.Add(new Permission(PageState.Site.SiteId, EntityNames.Page, PageState.Page.PageId, PermissionNames.View, RoleNames.Registered, null, true));
|
permissions.Add(new Permission(PageState.Page.SiteId, EntityNames.Page, PageState.Page.PageId, PermissionNames.View, RoleNames.Registered, null, true));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case "unpublish":
|
case "unpublish":
|
||||||
|
@ -1,21 +1,29 @@
|
|||||||
@namespace Oqtane.Themes.Controls
|
|
||||||
@inherits ThemeControlBase
|
|
||||||
@using System.Globalization
|
@using System.Globalization
|
||||||
@using Microsoft.AspNetCore.Localization
|
@using Microsoft.AspNetCore.Localization
|
||||||
|
@using Microsoft.AspNetCore.Http
|
||||||
@using Oqtane.Models
|
@using Oqtane.Models
|
||||||
|
@namespace Oqtane.Themes.Controls
|
||||||
|
@inherits ThemeControlBase
|
||||||
@inject ILanguageService LanguageService
|
@inject ILanguageService LanguageService
|
||||||
@inject NavigationManager NavigationManager
|
@inject NavigationManager NavigationManager
|
||||||
|
|
||||||
@if (_supportedCultures?.Count() > 1)
|
@if (_supportedCultures?.Count() > 1)
|
||||||
{
|
{
|
||||||
<div class="btn-group pe-1" role="group">
|
<div class="btn-group pe-1" role="group">
|
||||||
<button id="btnCultures" type="button" class="btn btn-outline-secondary dropdown-toggle" data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
|
<button id="btnCultures" type="button" class="btn @ButtonClass dropdown-toggle" data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
|
||||||
<span class="oi oi-globe"></span>
|
<span class="oi oi-globe"></span>
|
||||||
</button>
|
</button>
|
||||||
<div class="dropdown-menu @MenuAlignment" aria-labelledby="btnCultures">
|
<div class="dropdown-menu @MenuAlignment" aria-labelledby="btnCultures">
|
||||||
@foreach (var culture in _supportedCultures)
|
@foreach (var culture in _supportedCultures)
|
||||||
{
|
{
|
||||||
<a class="dropdown-item @(CultureInfo.CurrentUICulture.Name == culture.Name ? "active" : String.Empty)" href="#" @onclick="@(async e => await SetCultureAsync(culture.Name))">@culture.DisplayName</a>
|
@if (PageState.RenderMode == RenderModes.Interactive)
|
||||||
|
{
|
||||||
|
<a class="dropdown-item @(CultureInfo.CurrentUICulture.Name == culture.Name ? "active" : String.Empty)" href="#" @onclick="@(async e => await SetCultureAsync(culture.Name))" @onclick:preventDefault="true">@culture.DisplayName</a>
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
<a class="dropdown-item @(CultureInfo.CurrentUICulture.Name == culture.Name ? "active" : String.Empty)" href="@NavigateUrl(PageState.Page.Path, "culture=" + culture.Name)">@culture.DisplayName</a>
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -23,9 +31,15 @@
|
|||||||
|
|
||||||
@code{
|
@code{
|
||||||
private IEnumerable<Culture> _supportedCultures;
|
private IEnumerable<Culture> _supportedCultures;
|
||||||
|
private string MenuAlignment = string.Empty;
|
||||||
|
|
||||||
[Parameter]
|
[Parameter]
|
||||||
public string DropdownAlignment { get; set; } = string.Empty; // Empty or Left or Right
|
public string DropdownAlignment { get; set; } = string.Empty; // Empty or Left or Right
|
||||||
private string MenuAlignment = string.Empty;
|
[Parameter]
|
||||||
|
public string ButtonClass { get; set; } = "btn-outline-secondary";
|
||||||
|
|
||||||
|
[CascadingParameter]
|
||||||
|
HttpContext HttpContext { get; set; }
|
||||||
|
|
||||||
protected override void OnParametersSet()
|
protected override void OnParametersSet()
|
||||||
{
|
{
|
||||||
@ -33,16 +47,26 @@
|
|||||||
|
|
||||||
var languages = PageState.Languages;
|
var languages = PageState.Languages;
|
||||||
_supportedCultures = languages.Select(l => new Culture { Name = l.Code, DisplayName = l.Name });
|
_supportedCultures = languages.Select(l => new Culture { Name = l.Code, DisplayName = l.Name });
|
||||||
|
|
||||||
|
if (PageState.QueryString.ContainsKey("culture"))
|
||||||
|
{
|
||||||
|
var culture = PageState.QueryString["culture"];
|
||||||
|
if (_supportedCultures.Any(item => item.Name == culture))
|
||||||
|
{
|
||||||
|
var localizationCookieValue = CookieRequestCultureProvider.MakeCookieValue(new RequestCulture(culture));
|
||||||
|
HttpContext.Response.Cookies.Append(CookieRequestCultureProvider.DefaultCookieName, localizationCookieValue, new CookieOptions { Path = "/", Expires = DateTimeOffset.UtcNow.AddYears(365) });
|
||||||
|
}
|
||||||
|
NavigationManager.NavigateTo(NavigationManager.Uri.Replace($"?culture={culture}", ""), forceLoad: true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task SetCultureAsync(string culture)
|
private async Task SetCultureAsync(string culture)
|
||||||
{
|
{
|
||||||
if (culture != CultureInfo.CurrentUICulture.Name)
|
if (culture != CultureInfo.CurrentUICulture.Name)
|
||||||
{
|
{
|
||||||
var interop = new Interop(JSRuntime);
|
|
||||||
var localizationCookieValue = CookieRequestCultureProvider.MakeCookieValue(new RequestCulture(culture));
|
var localizationCookieValue = CookieRequestCultureProvider.MakeCookieValue(new RequestCulture(culture));
|
||||||
|
var interop = new Interop(JSRuntime);
|
||||||
await interop.SetCookie(CookieRequestCultureProvider.DefaultCookieName, localizationCookieValue, 360);
|
await interop.SetCookie(CookieRequestCultureProvider.DefaultCookieName, localizationCookieValue, 360);
|
||||||
|
|
||||||
NavigationManager.NavigateTo(NavigationManager.Uri, forceLoad: true);
|
NavigationManager.NavigateTo(NavigationManager.Uri, forceLoad: true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -59,7 +59,7 @@ namespace Oqtane.Themes.Controls
|
|||||||
logouturl = Utilities.TenantUrl(PageState.Alias, "/pages/logout/");
|
logouturl = Utilities.TenantUrl(PageState.Alias, "/pages/logout/");
|
||||||
|
|
||||||
// verify anonymous users can access current page
|
// verify anonymous users can access current page
|
||||||
if (UserSecurity.IsAuthorized(null, PermissionNames.View, PageState.Page.PermissionList) && Utilities.IsPageModuleVisible(PageState.Page.EffectiveDate, PageState.Page.ExpiryDate))
|
if (UserSecurity.IsAuthorized(null, PermissionNames.View, PageState.Page.PermissionList) && Utilities.IsEffectiveAndNotExpired(PageState.Page.EffectiveDate, PageState.Page.ExpiryDate))
|
||||||
{
|
{
|
||||||
returnurl = PageState.Route.PathAndQuery;
|
returnurl = PageState.Route.PathAndQuery;
|
||||||
}
|
}
|
||||||
|
61
Oqtane.Client/Themes/Controls/Theme/Search.razor
Normal file
61
Oqtane.Client/Themes/Controls/Theme/Search.razor
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
@namespace Oqtane.Themes.Controls
|
||||||
|
@using System.Net
|
||||||
|
@using Microsoft.AspNetCore.Http
|
||||||
|
@inherits ThemeControlBase
|
||||||
|
@inject IStringLocalizer<Search> Localizer
|
||||||
|
@inject NavigationManager NavigationManager
|
||||||
|
|
||||||
|
@if (_searchResultsPage != null)
|
||||||
|
{
|
||||||
|
<span class="app-search @CssClass">
|
||||||
|
<form method="post" class="app-form-inline" @formname="@($"SearchForm")" @onsubmit="@PerformSearch" data-enhance>
|
||||||
|
<input type="hidden" name="@Constants.RequestVerificationToken" value="@SiteState.AntiForgeryToken" />
|
||||||
|
<input type="text" name="keywords" maxlength="50"
|
||||||
|
class="form-control d-inline-block pe-5 shadow-none"
|
||||||
|
@bind="_keywords"
|
||||||
|
placeholder="@Localizer["SearchPlaceHolder"]"
|
||||||
|
aria-label="Search" />
|
||||||
|
<button type="submit" class="btn btn-search">
|
||||||
|
<span class="oi oi-magnifying-glass align-middle"></span>
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
|
</span>
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@code {
|
||||||
|
private Page _searchResultsPage;
|
||||||
|
private string _keywords = "";
|
||||||
|
|
||||||
|
[Parameter]
|
||||||
|
public string CssClass { get; set; }
|
||||||
|
|
||||||
|
[Parameter]
|
||||||
|
public string SearchResultPagePath { get; set; } = "search";
|
||||||
|
|
||||||
|
[CascadingParameter]
|
||||||
|
HttpContext HttpContext { get; set; }
|
||||||
|
|
||||||
|
[SupplyParameterFromForm(FormName = "SearchForm")]
|
||||||
|
public string KeyWords { get => ""; set => _keywords = value; }
|
||||||
|
|
||||||
|
protected override void OnInitialized()
|
||||||
|
{
|
||||||
|
if(!string.IsNullOrEmpty(SearchResultPagePath))
|
||||||
|
{
|
||||||
|
_searchResultsPage = PageState.Pages.FirstOrDefault(i => i.Path == SearchResultPagePath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void PerformSearch()
|
||||||
|
{
|
||||||
|
if (_searchResultsPage != null)
|
||||||
|
{
|
||||||
|
var url = NavigateUrl(_searchResultsPage.Path, $"q={WebUtility.UrlEncode(_keywords)}");
|
||||||
|
NavigationManager.NavigateTo(url);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -17,9 +17,13 @@ namespace Oqtane.Themes.OqtaneTheme
|
|||||||
Resources = new List<Resource>()
|
Resources = new List<Resource>()
|
||||||
{
|
{
|
||||||
// obtained from https://cdnjs.com/libraries
|
// obtained from https://cdnjs.com/libraries
|
||||||
new Resource { ResourceType = ResourceType.Stylesheet, Url = "https://cdnjs.cloudflare.com/ajax/libs/bootswatch/5.3.2/cyborg/bootstrap.min.css", Integrity = "sha512-RfNxVfFNFgqk9MXO4TCKXYXn9hgc+keHCg3xFFGbnp2q7Cifda+YYzMTDHwsQtNx4DuqIMgfvZead7XOtB9CDQ==", CrossOrigin = "anonymous" },
|
new Resource { ResourceType = ResourceType.Stylesheet, Url = "https://cdnjs.cloudflare.com/ajax/libs/bootswatch/5.3.3/cyborg/bootstrap.min.css",
|
||||||
|
Integrity = "sha512-M+Wrv9LTvQe81gFD2ZE3xxPTN5V2n1iLCXsldIxXvfs6tP+6VihBCwCMBkkjkQUZVmEHBsowb9Vqsq1et1teEg==",
|
||||||
|
CrossOrigin = "anonymous" },
|
||||||
new Resource { ResourceType = ResourceType.Stylesheet, Url = "~/Theme.css" },
|
new Resource { ResourceType = ResourceType.Stylesheet, Url = "~/Theme.css" },
|
||||||
new Resource { ResourceType = ResourceType.Script, Url = "https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.3.2/js/bootstrap.bundle.min.js", Integrity = "sha512-X/YkDZyjTf4wyc2Vy16YGCPHwAY8rZJY+POgokZjQB2mhIRFJCckEGc6YyX9eNsPfn0PzThEuNs+uaomE5CO6A==", CrossOrigin = "anonymous", Location = ResourceLocation.Body }
|
new Resource { ResourceType = ResourceType.Script, Url = "https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.3.3/js/bootstrap.bundle.min.js",
|
||||||
|
Integrity = "sha512-7Pi/otdlbbCR+LnW+F7PwFcSDJOuUJB3OxtEHbg4vSMvzvJjde4Po1v4BR9Gdc9aXNUNFVUY+SK51wWT8WF0Gg==",
|
||||||
|
CrossOrigin = "anonymous", Location = ResourceLocation.Body },
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -6,7 +6,12 @@
|
|||||||
<nav class="navbar navbar-dark bg-primary fixed-top">
|
<nav class="navbar navbar-dark bg-primary fixed-top">
|
||||||
<Logo /><Menu Orientation="Horizontal" />
|
<Logo /><Menu Orientation="Horizontal" />
|
||||||
<div class="controls ms-auto">
|
<div class="controls ms-auto">
|
||||||
<div class="controls-group"><UserProfile ShowRegister="@_register" /> <Login ShowLogin="@_login" /> <ControlPanel LanguageDropdownAlignment="right" /></div>
|
<div class="controls-group">
|
||||||
|
<Search CssClass="me-3 text-center bg-primary" />
|
||||||
|
<UserProfile ShowRegister="@_register" />
|
||||||
|
<Login ShowLogin="@_login" />
|
||||||
|
<ControlPanel LanguageDropdownAlignment="right" />
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</nav>
|
</nav>
|
||||||
<div class="content">
|
<div class="content">
|
||||||
|
13
Oqtane.Client/UI/ModuleInstance.placeholder.cs
Normal file
13
Oqtane.Client/UI/ModuleInstance.placeholder.cs
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
// This is just a placeholder file
|
||||||
|
// It is necessary for the documentation to successfully build this project.
|
||||||
|
// Reason is that docfx will run the .net compiler and find references
|
||||||
|
// to this class in the project.
|
||||||
|
// But since the real class is just a .razor file, ATM docfx will fail.
|
||||||
|
//
|
||||||
|
// Note added 2024-06-27 by @iJungleboy.
|
||||||
|
// We hope that as .net and docfx improve, the razor-compiler will work in that scenario
|
||||||
|
// as well, and this file can be removed.
|
||||||
|
|
||||||
|
namespace Oqtane.UI;
|
||||||
|
|
||||||
|
public partial class ModuleInstance;
|
@ -1,25 +1,52 @@
|
|||||||
@namespace Oqtane.UI
|
@namespace Oqtane.UI
|
||||||
@inject SiteState SiteState
|
@inject SiteState SiteState
|
||||||
|
|
||||||
@if (PageState.RenderMode == RenderModes.Interactive || ModuleState.RenderMode == RenderModes.Static)
|
@if (_comment != null)
|
||||||
{
|
{
|
||||||
|
@((MarkupString)_comment)
|
||||||
|
@if (PageState.RenderMode == RenderModes.Interactive || ModuleState.RenderMode == RenderModes.Static)
|
||||||
|
{
|
||||||
<RenderModeBoundary ModuleState="@ModuleState" PageState="@PageState" SiteState="@SiteState" />
|
<RenderModeBoundary ModuleState="@ModuleState" PageState="@PageState" SiteState="@SiteState" />
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
<RenderModeBoundary ModuleState="@ModuleState" PageState="@PageState" SiteState="@SiteState" @rendermode="@InteractiveRenderMode.GetInteractiveRenderMode(PageState.Site.Runtime, PageState.Site.Prerender)" />
|
<RenderModeBoundary ModuleState="@ModuleState" PageState="@PageState" SiteState="@SiteState" @rendermode="InteractiveRenderMode.GetInteractiveRenderMode(PageState.Site.Runtime, _prerender)" />
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@code {
|
@code {
|
||||||
// this component is on the static side of the render mode boundary
|
|
||||||
// it passes state as serializable parameters across the boundary
|
|
||||||
|
|
||||||
[CascadingParameter]
|
[CascadingParameter]
|
||||||
protected PageState PageState { get; set; }
|
protected PageState PageState { get; set; }
|
||||||
|
|
||||||
[CascadingParameter]
|
[CascadingParameter]
|
||||||
private Module ModuleState { get; set; }
|
private Module ModuleState { get; set; }
|
||||||
|
|
||||||
|
private bool _prerender;
|
||||||
|
private string _comment;
|
||||||
|
|
||||||
|
protected override void OnParametersSet()
|
||||||
|
{
|
||||||
|
_prerender = ModuleState.Prerender ?? PageState.Site.Prerender;
|
||||||
|
|
||||||
|
_comment = "<!-- rendermode: ";
|
||||||
|
if (PageState.RenderMode == RenderModes.Static && ModuleState.RenderMode == RenderModes.Static)
|
||||||
|
{
|
||||||
|
_comment += RenderModes.Static;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_comment += $"{RenderModes.Interactive}:{PageState.Runtime} - prerender: {_prerender}";
|
||||||
|
}
|
||||||
|
_comment += " -->";
|
||||||
|
|
||||||
|
if (PageState.RenderMode == RenderModes.Static && ModuleState.RenderMode == RenderModes.Interactive)
|
||||||
|
{
|
||||||
|
// trim PageState to mitigate page bloat caused by Blazor serializing/encrypting state when crossing render mode boundaries
|
||||||
|
// please note that this performance optimization results in the PageState.Pages property not being available for use in Interactive components
|
||||||
|
PageState.Site.Pages = new List<Page>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
[Obsolete("AddModuleMessage is deprecated. Use AddModuleMessage in ModuleBase instead.", false)]
|
[Obsolete("AddModuleMessage is deprecated. Use AddModuleMessage in ModuleBase instead.", false)]
|
||||||
public void AddModuleMessage(string message, MessageType type)
|
public void AddModuleMessage(string message, MessageType type)
|
||||||
|
@ -9,6 +9,7 @@ namespace Oqtane.UI
|
|||||||
public Alias Alias { get; set; }
|
public Alias Alias { get; set; }
|
||||||
public Site Site { get; set; }
|
public Site Site { get; set; }
|
||||||
public Page Page { get; set; }
|
public Page Page { get; set; }
|
||||||
|
public List<Module> Modules { get; set; }
|
||||||
public User User { get; set; }
|
public User User { get; set; }
|
||||||
public Uri Uri { get; set; }
|
public Uri Uri { get; set; }
|
||||||
public Route Route { get; set; }
|
public Route Route { get; set; }
|
||||||
@ -29,15 +30,11 @@ namespace Oqtane.UI
|
|||||||
|
|
||||||
public List<Page> Pages
|
public List<Page> Pages
|
||||||
{
|
{
|
||||||
get { return Site.Pages; }
|
get { return Site?.Pages; }
|
||||||
}
|
|
||||||
public List<Module> Modules
|
|
||||||
{
|
|
||||||
get { return Site.Modules; }
|
|
||||||
}
|
}
|
||||||
public List<Language> Languages
|
public List<Language> Languages
|
||||||
{
|
{
|
||||||
get { return Site.Languages; }
|
get { return Site?.Languages; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -43,7 +43,7 @@ else
|
|||||||
|
|
||||||
DynamicComponent = builder =>
|
DynamicComponent = builder =>
|
||||||
{
|
{
|
||||||
foreach (Module module in PageState.Modules.Where(item => item.PageId == PageState.Page.PageId))
|
foreach (Module module in PageState.Modules)
|
||||||
{
|
{
|
||||||
// set renderid - this allows the framework to determine which components should be rendered when PageState changes
|
// set renderid - this allows the framework to determine which components should be rendered when PageState changes
|
||||||
if (module.RenderId != PageState.RenderId)
|
if (module.RenderId != PageState.RenderId)
|
||||||
|
13
Oqtane.Client/UI/RenderModeBoundary.placeholder.cs
Normal file
13
Oqtane.Client/UI/RenderModeBoundary.placeholder.cs
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
// This is just a placeholder file
|
||||||
|
// It is necessary for the documentation to successfully build this project.
|
||||||
|
// Reason is that docfx will run the .net compiler and find references
|
||||||
|
// to this class in the project.
|
||||||
|
// But since the real class is just a .razor file, ATM docfx will fail.
|
||||||
|
//
|
||||||
|
// Note added 2024-06-27 by @iJungleboy.
|
||||||
|
// We hope that as .net and docfx improve, the razor-compiler will work in that scenario
|
||||||
|
// as well, and this file can be removed.
|
||||||
|
|
||||||
|
namespace Oqtane.UI;
|
||||||
|
|
||||||
|
public partial class RenderModeBoundary;
|
@ -10,14 +10,19 @@
|
|||||||
{
|
{
|
||||||
@if (ModuleType != null)
|
@if (ModuleType != null)
|
||||||
{
|
{
|
||||||
@((MarkupString)$"<!-- rendermode: {ModuleState.RenderMode} -->")
|
@if (!string.IsNullOrEmpty(_messageContent) && _messagePosition == "top")
|
||||||
<ModuleMessage @ref="moduleMessageTop" Message="@_messageContent" Type="@_messageType" />
|
{
|
||||||
|
<ModuleMessage Message="@_messageContent" Type="@_messageType" Parent="@this" />
|
||||||
|
}
|
||||||
@DynamicComponent
|
@DynamicComponent
|
||||||
@if (_progressIndicator)
|
@if (_progressIndicator)
|
||||||
{
|
{
|
||||||
<div class="app-progress-indicator"></div>
|
<div class="app-progress-indicator"></div>
|
||||||
}
|
}
|
||||||
<ModuleMessage @ref="moduleMessageBottom" Message="@_messageContent" Type="@_messageType" />
|
@if (!string.IsNullOrEmpty(_messageContent) && _messagePosition == "bottom")
|
||||||
|
{
|
||||||
|
<ModuleMessage Message="@_messageContent" Type="@_messageType" Parent="@this" />
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -42,8 +47,6 @@
|
|||||||
private string _messagePosition;
|
private string _messagePosition;
|
||||||
private bool _progressIndicator = false;
|
private bool _progressIndicator = false;
|
||||||
private string _error;
|
private string _error;
|
||||||
private ModuleMessage moduleMessageTop;
|
|
||||||
private ModuleMessage moduleMessageBottom;
|
|
||||||
|
|
||||||
[Parameter]
|
[Parameter]
|
||||||
public SiteState SiteState { get; set; }
|
public SiteState SiteState { get; set; }
|
||||||
@ -103,13 +106,18 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void AddModuleMessage(string message, MessageType type, string position)
|
public void AddModuleMessage(string message, MessageType type, string position)
|
||||||
|
{
|
||||||
|
if(message != _messageContent
|
||||||
|
|| type != _messageType
|
||||||
|
|| position != _messagePosition)
|
||||||
{
|
{
|
||||||
_messageContent = message;
|
_messageContent = message;
|
||||||
_messageType = type;
|
_messageType = type;
|
||||||
_messagePosition = position;
|
_messagePosition = position;
|
||||||
_progressIndicator = false;
|
_progressIndicator = false;
|
||||||
|
|
||||||
Refresh();
|
StateHasChanged();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ShowProgressIndicator()
|
public void ShowProgressIndicator()
|
||||||
@ -124,25 +132,10 @@
|
|||||||
StateHasChanged();
|
StateHasChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void DismissMessage()
|
public void DismissMessage()
|
||||||
{
|
{
|
||||||
_messageContent = "";
|
_messageContent = "";
|
||||||
}
|
StateHasChanged();
|
||||||
|
|
||||||
private void Refresh()
|
|
||||||
{
|
|
||||||
var updateTop = string.IsNullOrEmpty(_messageContent) || _messagePosition == "top";
|
|
||||||
var updateBottom = string.IsNullOrEmpty(_messageContent) || _messagePosition == "bottom";
|
|
||||||
|
|
||||||
if (updateTop && moduleMessageTop != null)
|
|
||||||
{
|
|
||||||
moduleMessageTop.RefreshMessage(_messageContent, _messageType);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (updateBottom && moduleMessageBottom != null)
|
|
||||||
{
|
|
||||||
moduleMessageBottom.RefreshMessage(_messageContent, _messageType);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override async Task OnErrorAsync(Exception exception)
|
protected override async Task OnErrorAsync(Exception exception)
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
@using System.Diagnostics.CodeAnalysis
|
@using System.Diagnostics.CodeAnalysis
|
||||||
@using System.Net
|
@using System.Net
|
||||||
@using Microsoft.AspNetCore.Http
|
@using Microsoft.AspNetCore.Http
|
||||||
|
@using System.Globalization
|
||||||
|
@using System.Security.Claims
|
||||||
@namespace Oqtane.UI
|
@namespace Oqtane.UI
|
||||||
@inject AuthenticationStateProvider AuthenticationStateProvider
|
@inject AuthenticationStateProvider AuthenticationStateProvider
|
||||||
@inject SiteState SiteState
|
@inject SiteState SiteState
|
||||||
@ -95,6 +97,7 @@
|
|||||||
{
|
{
|
||||||
Site site = null;
|
Site site = null;
|
||||||
Page page = null;
|
Page page = null;
|
||||||
|
List<Module> modules = null;
|
||||||
User user = null;
|
User user = null;
|
||||||
var editmode = false;
|
var editmode = false;
|
||||||
var refresh = false;
|
var refresh = false;
|
||||||
@ -103,7 +106,7 @@
|
|||||||
_error = "";
|
_error = "";
|
||||||
|
|
||||||
Route route = new Route(_absoluteUri, SiteState.Alias.Path);
|
Route route = new Route(_absoluteUri, SiteState.Alias.Path);
|
||||||
int moduleid = int.Parse(route.ModuleId);
|
int moduleid = int.Parse(route.ModuleId, CultureInfo.InvariantCulture);
|
||||||
var action = route.Action;
|
var action = route.Action;
|
||||||
|
|
||||||
var querystring = Utilities.ParseQueryString(route.Query);
|
var querystring = Utilities.ParseQueryString(route.Query);
|
||||||
@ -157,7 +160,8 @@
|
|||||||
if (authState.User.Identity.IsAuthenticated && authState.User.Claims.Any(item => item.Type == "sitekey" && item.Value == SiteState.Alias.SiteKey))
|
if (authState.User.Identity.IsAuthenticated && authState.User.Claims.Any(item => item.Type == "sitekey" && item.Value == SiteState.Alias.SiteKey))
|
||||||
{
|
{
|
||||||
// get user
|
// get user
|
||||||
user = await UserService.GetUserAsync(authState.User.Identity.Name, SiteState.Alias.SiteId);
|
var userid = int.Parse(authState.User.Claims.First(item => item.Type == ClaimTypes.NameIdentifier).Value);
|
||||||
|
user = await UserService.GetUserAsync(userid, SiteState.Alias.SiteId);
|
||||||
if (user != null)
|
if (user != null)
|
||||||
{
|
{
|
||||||
user.IsAuthenticated = authState.User.Identity.IsAuthenticated;
|
user.IsAuthenticated = authState.User.Identity.IsAuthenticated;
|
||||||
@ -211,7 +215,7 @@
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (PageState == null || refresh || PageState.Page.Path != route.PagePath)
|
if (refresh || PageState == null || PageState.Page.Path != route.PagePath)
|
||||||
{
|
{
|
||||||
page = site.Pages.FirstOrDefault(item => item.Path.Equals(route.PagePath, StringComparison.OrdinalIgnoreCase));
|
page = site.Pages.FirstOrDefault(item => item.Path.Equals(route.PagePath, StringComparison.OrdinalIgnoreCase));
|
||||||
}
|
}
|
||||||
@ -252,31 +256,41 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
// check if user is authorized to view page
|
// check if user is authorized to view page
|
||||||
if (page != null && UserSecurity.IsAuthorized(user, PermissionNames.View, page.PermissionList) && (Utilities.IsPageModuleVisible(page.EffectiveDate, page.ExpiryDate) || UserSecurity.IsAuthorized(user, PermissionNames.Edit, page.PermissionList)))
|
if (page != null && UserSecurity.IsAuthorized(user, PermissionNames.View, page.PermissionList) && (Utilities.IsEffectiveAndNotExpired(page.EffectiveDate, page.ExpiryDate) || UserSecurity.IsAuthorized(user, PermissionNames.Edit, page.PermissionList)))
|
||||||
{
|
{
|
||||||
// edit mode
|
// edit mode
|
||||||
if (user != null)
|
if (user != null)
|
||||||
{
|
{
|
||||||
if (querystring.ContainsKey("editmode") && querystring["edit"] == "true")
|
var editpageid = user.Settings.ContainsKey("CP-editmode") ? int.Parse(user.Settings["CP-editmode"], CultureInfo.InvariantCulture) : -1;
|
||||||
|
if ((querystring.ContainsKey("edit") && querystring["edit"] == "true") || page.PageId == editpageid)
|
||||||
{
|
{
|
||||||
editmode = true;
|
editmode = true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
editmode = (page.PageId == ((user.Settings.ContainsKey("CP-editmode")) ? int.Parse(user.Settings["CP-editmode"]) : -1));
|
if (editpageid != -1)
|
||||||
if (!editmode)
|
|
||||||
{
|
{
|
||||||
var userSettings = new Dictionary<string, string> { { "CP-editmode", "-1" } };
|
// reset edit mode page
|
||||||
await SettingService.UpdateUserSettingsAsync(userSettings, user.UserId);
|
await SettingService.AddOrUpdateSettingAsync(EntityNames.User, user.UserId, "CP-editmode", "-1", false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// get modules for current page
|
||||||
|
if (refresh || PageState.Modules == null || !PageState.Modules.Any() || PageState.Modules.First().PageId != page.PageId)
|
||||||
|
{
|
||||||
|
modules = await SiteService.GetModulesAsync(site.SiteId, page.PageId);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
modules = PageState.Modules;
|
||||||
|
}
|
||||||
|
|
||||||
// load additional metadata for current page
|
// load additional metadata for current page
|
||||||
page = ProcessPage(page, site, user, SiteState.Alias);
|
page = ProcessPage(page, site, user, SiteState.Alias);
|
||||||
|
|
||||||
// load additional metadata for modules
|
// load additional metadata for modules
|
||||||
(page, site.Modules) = ProcessModules(page, site.Modules, moduleid, action, (!string.IsNullOrEmpty(page.DefaultContainerType)) ? page.DefaultContainerType : site.DefaultContainerType, SiteState.Alias);
|
(page, modules) = ProcessModules(page, modules, moduleid, action, (!string.IsNullOrEmpty(page.DefaultContainerType)) ? page.DefaultContainerType : site.DefaultContainerType, SiteState.Alias);
|
||||||
|
|
||||||
// populate page state (which acts as a client-side cache for subsequent requests)
|
// populate page state (which acts as a client-side cache for subsequent requests)
|
||||||
_pagestate = new PageState
|
_pagestate = new PageState
|
||||||
@ -284,6 +298,7 @@
|
|||||||
Alias = SiteState.Alias,
|
Alias = SiteState.Alias,
|
||||||
Site = site,
|
Site = site,
|
||||||
Page = page,
|
Page = page,
|
||||||
|
Modules = modules,
|
||||||
User = user,
|
User = user,
|
||||||
Uri = new Uri(_absoluteUri, UriKind.Absolute),
|
Uri = new Uri(_absoluteUri, UriKind.Absolute),
|
||||||
Route = route,
|
Route = route,
|
||||||
@ -476,6 +491,7 @@
|
|||||||
// retrieve module component resources
|
// retrieve module component resources
|
||||||
var moduleobject = Activator.CreateInstance(moduletype) as IModuleControl;
|
var moduleobject = Activator.CreateInstance(moduletype) as IModuleControl;
|
||||||
module.RenderMode = moduleobject.RenderMode;
|
module.RenderMode = moduleobject.RenderMode;
|
||||||
|
module.Prerender = moduleobject.Prerender;
|
||||||
|
|
||||||
page.Resources = ManagePageResources(page.Resources, moduleobject.Resources, ResourceLevel.Module, alias, "Modules", moduletype.Namespace);
|
page.Resources = ManagePageResources(page.Resources, moduleobject.Resources, ResourceLevel.Module, alias, "Modules", moduletype.Namespace);
|
||||||
if (action.ToLower() == "settings" && module.ModuleDefinition != null)
|
if (action.ToLower() == "settings" && module.ModuleDefinition != null)
|
||||||
@ -549,7 +565,7 @@
|
|||||||
{
|
{
|
||||||
foreach (var resource in resources)
|
foreach (var resource in resources)
|
||||||
{
|
{
|
||||||
if (resource.Level != ResourceLevel.Site)
|
if (resource.ResourceType == ResourceType.Stylesheet || resource.Level != ResourceLevel.Site)
|
||||||
{
|
{
|
||||||
if (resource.Url.StartsWith("~"))
|
if (resource.Url.StartsWith("~"))
|
||||||
{
|
{
|
||||||
|
@ -66,21 +66,17 @@
|
|||||||
{
|
{
|
||||||
if (!string.IsNullOrEmpty(content))
|
if (!string.IsNullOrEmpty(content))
|
||||||
{
|
{
|
||||||
// format head content, remove scripts, and filter duplicate elements
|
if (PageState.RenderMode == RenderModes.Interactive)
|
||||||
content = content.Replace("\n", "");
|
{
|
||||||
var index = content.IndexOf("<");
|
// remove scripts
|
||||||
|
var index = content.IndexOf("<script");
|
||||||
while (index >= 0)
|
while (index >= 0)
|
||||||
{
|
{
|
||||||
var element = content.Substring(index, content.IndexOf(">", index) - index + 1);
|
content = content.Remove(index, content.IndexOf("</script>") + 9 - index);
|
||||||
if (!string.IsNullOrEmpty(element) && (PageState.RenderMode == RenderModes.Static || (!element.ToLower().StartsWith("<script") && !element.ToLower().StartsWith("</script"))))
|
index = content.IndexOf("<script");
|
||||||
{
|
|
||||||
if (!headcontent.Contains(element))
|
|
||||||
{
|
|
||||||
headcontent += element + "\n";
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
index = content.IndexOf("<", index + 1);
|
headcontent += content + "\n";
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return headcontent;
|
return headcontent;
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net8.0</TargetFramework>
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
<Version>5.1.1</Version>
|
<Version>5.2.0</Version>
|
||||||
<Product>Oqtane</Product>
|
<Product>Oqtane</Product>
|
||||||
<Authors>Shaun Walker</Authors>
|
<Authors>Shaun Walker</Authors>
|
||||||
<Company>.NET Foundation</Company>
|
<Company>.NET Foundation</Company>
|
||||||
@ -10,7 +10,7 @@
|
|||||||
<Copyright>.NET Foundation</Copyright>
|
<Copyright>.NET Foundation</Copyright>
|
||||||
<PackageProjectUrl>https://www.oqtane.org</PackageProjectUrl>
|
<PackageProjectUrl>https://www.oqtane.org</PackageProjectUrl>
|
||||||
<PackageLicenseUrl>https://github.com/oqtane/oqtane.framework/blob/dev/LICENSE</PackageLicenseUrl>
|
<PackageLicenseUrl>https://github.com/oqtane/oqtane.framework/blob/dev/LICENSE</PackageLicenseUrl>
|
||||||
<PackageReleaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v5.1.1</PackageReleaseNotes>
|
<PackageReleaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v5.2.0</PackageReleaseNotes>
|
||||||
<RepositoryUrl>https://github.com/oqtane/oqtane.framework</RepositoryUrl>
|
<RepositoryUrl>https://github.com/oqtane/oqtane.framework</RepositoryUrl>
|
||||||
<RepositoryType>Git</RepositoryType>
|
<RepositoryType>Git</RepositoryType>
|
||||||
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
|
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
|
||||||
@ -33,8 +33,8 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="MySql.EntityFrameworkCore" Version="8.0.0" />
|
<PackageReference Include="MySql.EntityFrameworkCore" Version="8.0.5" />
|
||||||
<PackageReference Include="MySql.Data" Version="8.3.0" />
|
<PackageReference Include="MySql.Data" Version="9.0.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net8.0</TargetFramework>
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
<Version>5.1.1</Version>
|
<Version>5.2.1</Version>
|
||||||
<Product>Oqtane</Product>
|
<Product>Oqtane</Product>
|
||||||
<Authors>Shaun Walker</Authors>
|
<Authors>Shaun Walker</Authors>
|
||||||
<Company>.NET Foundation</Company>
|
<Company>.NET Foundation</Company>
|
||||||
@ -10,7 +10,7 @@
|
|||||||
<Copyright>.NET Foundation</Copyright>
|
<Copyright>.NET Foundation</Copyright>
|
||||||
<PackageProjectUrl>https://www.oqtane.org</PackageProjectUrl>
|
<PackageProjectUrl>https://www.oqtane.org</PackageProjectUrl>
|
||||||
<PackageLicenseUrl>https://github.com/oqtane/oqtane.framework/blob/dev/LICENSE</PackageLicenseUrl>
|
<PackageLicenseUrl>https://github.com/oqtane/oqtane.framework/blob/dev/LICENSE</PackageLicenseUrl>
|
||||||
<PackageReleaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v5.1.1</PackageReleaseNotes>
|
<PackageReleaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v5.2.1</PackageReleaseNotes>
|
||||||
<RepositoryUrl>https://github.com/oqtane/oqtane.framework</RepositoryUrl>
|
<RepositoryUrl>https://github.com/oqtane/oqtane.framework</RepositoryUrl>
|
||||||
<RepositoryType>Git</RepositoryType>
|
<RepositoryType>Git</RepositoryType>
|
||||||
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
|
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
|
||||||
@ -34,8 +34,8 @@
|
|||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="EFCore.NamingConventions" Version="8.0.3" />
|
<PackageReference Include="EFCore.NamingConventions" Version="8.0.3" />
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="8.0.4" />
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="8.0.8" />
|
||||||
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="8.0.2" />
|
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="8.0.4" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net8.0</TargetFramework>
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
<Version>5.1.1</Version>
|
<Version>5.2.1</Version>
|
||||||
<Product>Oqtane</Product>
|
<Product>Oqtane</Product>
|
||||||
<Authors>Shaun Walker</Authors>
|
<Authors>Shaun Walker</Authors>
|
||||||
<Company>.NET Foundation</Company>
|
<Company>.NET Foundation</Company>
|
||||||
@ -10,7 +10,7 @@
|
|||||||
<Copyright>.NET Foundation</Copyright>
|
<Copyright>.NET Foundation</Copyright>
|
||||||
<PackageProjectUrl>https://www.oqtane.org</PackageProjectUrl>
|
<PackageProjectUrl>https://www.oqtane.org</PackageProjectUrl>
|
||||||
<PackageLicenseUrl>https://github.com/oqtane/oqtane.framework/blob/dev/LICENSE</PackageLicenseUrl>
|
<PackageLicenseUrl>https://github.com/oqtane/oqtane.framework/blob/dev/LICENSE</PackageLicenseUrl>
|
||||||
<PackageReleaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v5.1.1</PackageReleaseNotes>
|
<PackageReleaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v5.2.1</PackageReleaseNotes>
|
||||||
<RepositoryUrl>https://github.com/oqtane/oqtane.framework</RepositoryUrl>
|
<RepositoryUrl>https://github.com/oqtane/oqtane.framework</RepositoryUrl>
|
||||||
<RepositoryType>Git</RepositoryType>
|
<RepositoryType>Git</RepositoryType>
|
||||||
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
|
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
|
||||||
@ -33,7 +33,7 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="8.0.4" />
|
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="8.0.8" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net8.0</TargetFramework>
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
<Version>5.1.1</Version>
|
<Version>5.2.1</Version>
|
||||||
<Product>Oqtane</Product>
|
<Product>Oqtane</Product>
|
||||||
<Authors>Shaun Walker</Authors>
|
<Authors>Shaun Walker</Authors>
|
||||||
<Company>.NET Foundation</Company>
|
<Company>.NET Foundation</Company>
|
||||||
@ -10,7 +10,7 @@
|
|||||||
<Copyright>.NET Foundation</Copyright>
|
<Copyright>.NET Foundation</Copyright>
|
||||||
<PackageProjectUrl>https://www.oqtane.org</PackageProjectUrl>
|
<PackageProjectUrl>https://www.oqtane.org</PackageProjectUrl>
|
||||||
<PackageLicenseUrl>https://github.com/oqtane/oqtane.framework/blob/dev/LICENSE</PackageLicenseUrl>
|
<PackageLicenseUrl>https://github.com/oqtane/oqtane.framework/blob/dev/LICENSE</PackageLicenseUrl>
|
||||||
<PackageReleaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v5.1.1</PackageReleaseNotes>
|
<PackageReleaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v5.2.1</PackageReleaseNotes>
|
||||||
<RepositoryUrl>https://github.com/oqtane/oqtane.framework</RepositoryUrl>
|
<RepositoryUrl>https://github.com/oqtane/oqtane.framework</RepositoryUrl>
|
||||||
<RepositoryType>Git</RepositoryType>
|
<RepositoryType>Git</RepositoryType>
|
||||||
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
|
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
|
||||||
@ -33,7 +33,7 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="8.0.4" />
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="8.0.8" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
<!-- <TargetFrameworks>net8.0-android;net8.0-ios;net8.0-maccatalyst</TargetFrameworks> -->
|
<!-- <TargetFrameworks>net8.0-android;net8.0-ios;net8.0-maccatalyst</TargetFrameworks> -->
|
||||||
<!-- <TargetFrameworks>$(TargetFrameworks);net8.0-tizen</TargetFrameworks> -->
|
<!-- <TargetFrameworks>$(TargetFrameworks);net8.0-tizen</TargetFrameworks> -->
|
||||||
<OutputType>Exe</OutputType>
|
<OutputType>Exe</OutputType>
|
||||||
<Version>5.1.1</Version>
|
<Version>5.2.1</Version>
|
||||||
<Product>Oqtane</Product>
|
<Product>Oqtane</Product>
|
||||||
<Authors>Shaun Walker</Authors>
|
<Authors>Shaun Walker</Authors>
|
||||||
<Company>.NET Foundation</Company>
|
<Company>.NET Foundation</Company>
|
||||||
@ -14,7 +14,7 @@
|
|||||||
<Copyright>.NET Foundation</Copyright>
|
<Copyright>.NET Foundation</Copyright>
|
||||||
<PackageProjectUrl>https://www.oqtane.org</PackageProjectUrl>
|
<PackageProjectUrl>https://www.oqtane.org</PackageProjectUrl>
|
||||||
<PackageLicenseUrl>https://github.com/oqtane/oqtane.framework/blob/dev/LICENSE</PackageLicenseUrl>
|
<PackageLicenseUrl>https://github.com/oqtane/oqtane.framework/blob/dev/LICENSE</PackageLicenseUrl>
|
||||||
<PackageReleaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v5.1.1</PackageReleaseNotes>
|
<PackageReleaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v5.2.1</PackageReleaseNotes>
|
||||||
<RepositoryUrl>https://github.com/oqtane/oqtane.framework</RepositoryUrl>
|
<RepositoryUrl>https://github.com/oqtane/oqtane.framework</RepositoryUrl>
|
||||||
<RepositoryType>Git</RepositoryType>
|
<RepositoryType>Git</RepositoryType>
|
||||||
<RootNamespace>Oqtane.Maui</RootNamespace>
|
<RootNamespace>Oqtane.Maui</RootNamespace>
|
||||||
@ -31,7 +31,7 @@
|
|||||||
<ApplicationIdGuid>0E29FC31-1B83-48ED-B6E0-9F3C67B775D4</ApplicationIdGuid>
|
<ApplicationIdGuid>0E29FC31-1B83-48ED-B6E0-9F3C67B775D4</ApplicationIdGuid>
|
||||||
|
|
||||||
<!-- Versions -->
|
<!-- Versions -->
|
||||||
<ApplicationDisplayVersion>5.1.1</ApplicationDisplayVersion>
|
<ApplicationDisplayVersion>5.2.1</ApplicationDisplayVersion>
|
||||||
<ApplicationVersion>1</ApplicationVersion>
|
<ApplicationVersion>1</ApplicationVersion>
|
||||||
|
|
||||||
<SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'ios'">14.2</SupportedOSPlatformVersion>
|
<SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'ios'">14.2</SupportedOSPlatformVersion>
|
||||||
@ -65,15 +65,15 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Components.Authorization" Version="8.0.4" />
|
<PackageReference Include="Microsoft.AspNetCore.Components.Authorization" Version="8.0.8" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="8.0.4" />
|
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="8.0.8" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Localization" Version="2.2.0" />
|
<PackageReference Include="Microsoft.AspNetCore.Localization" Version="2.2.0" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Http" Version="8.0.0" />
|
<PackageReference Include="Microsoft.Extensions.Http" Version="8.0.0" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Localization" Version="8.0.4" />
|
<PackageReference Include="Microsoft.Extensions.Localization" Version="8.0.8" />
|
||||||
<PackageReference Include="System.Net.Http.Json" Version="8.0.0" />
|
<PackageReference Include="System.Net.Http.Json" Version="8.0.0" />
|
||||||
<PackageReference Include="Microsoft.Maui.Controls" Version="8.0.20" />
|
<PackageReference Include="Microsoft.Maui.Controls" Version="8.0.80" />
|
||||||
<PackageReference Include="Microsoft.Maui.Controls.Compatibility" Version="8.0.20" />
|
<PackageReference Include="Microsoft.Maui.Controls.Compatibility" Version="8.0.80" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Components.WebView.Maui" Version="8.0.20" />
|
<PackageReference Include="Microsoft.AspNetCore.Components.WebView.Maui" Version="8.0.80" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
|
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
|
||||||
<metadata>
|
<metadata>
|
||||||
<id>Oqtane.Client</id>
|
<id>Oqtane.Client</id>
|
||||||
<version>5.1.1</version>
|
<version>5.2.1</version>
|
||||||
<authors>Shaun Walker</authors>
|
<authors>Shaun Walker</authors>
|
||||||
<owners>.NET Foundation</owners>
|
<owners>.NET Foundation</owners>
|
||||||
<title>Oqtane Framework</title>
|
<title>Oqtane Framework</title>
|
||||||
@ -12,7 +12,7 @@
|
|||||||
<requireLicenseAcceptance>false</requireLicenseAcceptance>
|
<requireLicenseAcceptance>false</requireLicenseAcceptance>
|
||||||
<license type="expression">MIT</license>
|
<license type="expression">MIT</license>
|
||||||
<projectUrl>https://github.com/oqtane/oqtane.framework</projectUrl>
|
<projectUrl>https://github.com/oqtane/oqtane.framework</projectUrl>
|
||||||
<releaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v5.1.1</releaseNotes>
|
<releaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v5.2.1</releaseNotes>
|
||||||
<icon>icon.png</icon>
|
<icon>icon.png</icon>
|
||||||
<tags>oqtane</tags>
|
<tags>oqtane</tags>
|
||||||
</metadata>
|
</metadata>
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
|
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
|
||||||
<metadata>
|
<metadata>
|
||||||
<id>Oqtane.Framework</id>
|
<id>Oqtane.Framework</id>
|
||||||
<version>5.1.1</version>
|
<version>5.2.1</version>
|
||||||
<authors>Shaun Walker</authors>
|
<authors>Shaun Walker</authors>
|
||||||
<owners>.NET Foundation</owners>
|
<owners>.NET Foundation</owners>
|
||||||
<title>Oqtane Framework</title>
|
<title>Oqtane Framework</title>
|
||||||
@ -11,8 +11,8 @@
|
|||||||
<copyright>.NET Foundation</copyright>
|
<copyright>.NET Foundation</copyright>
|
||||||
<requireLicenseAcceptance>false</requireLicenseAcceptance>
|
<requireLicenseAcceptance>false</requireLicenseAcceptance>
|
||||||
<license type="expression">MIT</license>
|
<license type="expression">MIT</license>
|
||||||
<projectUrl>https://github.com/oqtane/oqtane.framework/releases/download/v5.1.1/Oqtane.Framework.5.1.1.Upgrade.zip</projectUrl>
|
<projectUrl>https://github.com/oqtane/oqtane.framework/releases/download/v5.2.1/Oqtane.Framework.5.2.1.Upgrade.zip</projectUrl>
|
||||||
<releaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v5.1.1</releaseNotes>
|
<releaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v5.2.1</releaseNotes>
|
||||||
<icon>icon.png</icon>
|
<icon>icon.png</icon>
|
||||||
<tags>oqtane framework</tags>
|
<tags>oqtane framework</tags>
|
||||||
</metadata>
|
</metadata>
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user