mirror of https://github.com/abpframework/abp.git
committed by
GitHub
81 changed files with 5720 additions and 40 deletions
File diff suppressed because it is too large
@ -0,0 +1,109 @@ |
|||
using System; |
|||
using Microsoft.EntityFrameworkCore.Migrations; |
|||
|
|||
namespace Volo.CmsKit.Migrations |
|||
{ |
|||
public partial class BlogPost_Author : Migration |
|||
{ |
|||
protected override void Up(MigrationBuilder migrationBuilder) |
|||
{ |
|||
migrationBuilder.DropForeignKey( |
|||
name: "FK_CmsBlogPosts_CmsUsers_CreatorId", |
|||
table: "CmsBlogPosts"); |
|||
|
|||
migrationBuilder.DropForeignKey( |
|||
name: "FK_CmsBlogPosts_CmsUsers_DeleterId", |
|||
table: "CmsBlogPosts"); |
|||
|
|||
migrationBuilder.DropForeignKey( |
|||
name: "FK_CmsBlogPosts_CmsUsers_LastModifierId", |
|||
table: "CmsBlogPosts"); |
|||
|
|||
migrationBuilder.DropIndex( |
|||
name: "IX_CmsBlogPosts_CreatorId", |
|||
table: "CmsBlogPosts"); |
|||
|
|||
migrationBuilder.DropIndex( |
|||
name: "IX_CmsBlogPosts_DeleterId", |
|||
table: "CmsBlogPosts"); |
|||
|
|||
migrationBuilder.DropIndex( |
|||
name: "IX_CmsBlogPosts_LastModifierId", |
|||
table: "CmsBlogPosts"); |
|||
|
|||
migrationBuilder.AddColumn<Guid>( |
|||
name: "AuthorId", |
|||
table: "CmsBlogPosts", |
|||
type: "uniqueidentifier", |
|||
nullable: false, |
|||
defaultValue: new Guid("00000000-0000-0000-0000-000000000000")); |
|||
|
|||
migrationBuilder.CreateIndex( |
|||
name: "IX_CmsBlogPosts_AuthorId", |
|||
table: "CmsBlogPosts", |
|||
column: "AuthorId"); |
|||
|
|||
migrationBuilder.AddForeignKey( |
|||
name: "FK_CmsBlogPosts_CmsUsers_AuthorId", |
|||
table: "CmsBlogPosts", |
|||
column: "AuthorId", |
|||
principalTable: "CmsUsers", |
|||
principalColumn: "Id", |
|||
onDelete: ReferentialAction.Cascade); |
|||
} |
|||
|
|||
protected override void Down(MigrationBuilder migrationBuilder) |
|||
{ |
|||
migrationBuilder.DropForeignKey( |
|||
name: "FK_CmsBlogPosts_CmsUsers_AuthorId", |
|||
table: "CmsBlogPosts"); |
|||
|
|||
migrationBuilder.DropIndex( |
|||
name: "IX_CmsBlogPosts_AuthorId", |
|||
table: "CmsBlogPosts"); |
|||
|
|||
migrationBuilder.DropColumn( |
|||
name: "AuthorId", |
|||
table: "CmsBlogPosts"); |
|||
|
|||
migrationBuilder.CreateIndex( |
|||
name: "IX_CmsBlogPosts_CreatorId", |
|||
table: "CmsBlogPosts", |
|||
column: "CreatorId"); |
|||
|
|||
migrationBuilder.CreateIndex( |
|||
name: "IX_CmsBlogPosts_DeleterId", |
|||
table: "CmsBlogPosts", |
|||
column: "DeleterId"); |
|||
|
|||
migrationBuilder.CreateIndex( |
|||
name: "IX_CmsBlogPosts_LastModifierId", |
|||
table: "CmsBlogPosts", |
|||
column: "LastModifierId"); |
|||
|
|||
migrationBuilder.AddForeignKey( |
|||
name: "FK_CmsBlogPosts_CmsUsers_CreatorId", |
|||
table: "CmsBlogPosts", |
|||
column: "CreatorId", |
|||
principalTable: "CmsUsers", |
|||
principalColumn: "Id", |
|||
onDelete: ReferentialAction.Restrict); |
|||
|
|||
migrationBuilder.AddForeignKey( |
|||
name: "FK_CmsBlogPosts_CmsUsers_DeleterId", |
|||
table: "CmsBlogPosts", |
|||
column: "DeleterId", |
|||
principalTable: "CmsUsers", |
|||
principalColumn: "Id", |
|||
onDelete: ReferentialAction.Restrict); |
|||
|
|||
migrationBuilder.AddForeignKey( |
|||
name: "FK_CmsBlogPosts_CmsUsers_LastModifierId", |
|||
table: "CmsBlogPosts", |
|||
column: "LastModifierId", |
|||
principalTable: "CmsUsers", |
|||
principalColumn: "Id", |
|||
onDelete: ReferentialAction.Restrict); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,21 @@ |
|||
The MIT License (MIT) |
|||
|
|||
Copyright (c) Simeon Velichkov <simeonvelichkov@gmail.com> |
|||
|
|||
Permission is hereby granted, free of charge, to any person obtaining a copy |
|||
of this software and associated documentation files (the "Software"), to deal |
|||
in the Software without restriction, including without limitation the rights |
|||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
|||
copies of the Software, and to permit persons to whom the Software is |
|||
furnished to do so, subject to the following conditions: |
|||
|
|||
The above copyright notice and this permission notice shall be included in all |
|||
copies or substantial portions of the Software. |
|||
|
|||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
|||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
|||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
|||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
|||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
|||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE |
|||
SOFTWARE. |
|||
@ -0,0 +1,90 @@ |
|||
|
|||
# slugify |
|||
|
|||
[![npm-version]][npm] [![travis-ci]][travis] [![coveralls-status]][coveralls] |
|||
|
|||
```js |
|||
var slugify = require('slugify') |
|||
|
|||
slugify('some string') // some-string |
|||
|
|||
// if you prefer something other than '-' as separator |
|||
slugify('some string', '_') // some_string |
|||
``` |
|||
|
|||
- Vanilla ES5 JavaScript |
|||
- No dependencies |
|||
- Coerces foreign symbols to their English equivalent (check out the [charMap][charmap] for more details) |
|||
- Works in the browser (window.slugify) and AMD/CommonJS-flavored module loaders |
|||
|
|||
## Options |
|||
|
|||
```js |
|||
slugify('some string', { |
|||
replacement: '-', // replace spaces with replacement character, defaults to `-` |
|||
remove: undefined, // remove characters that match regex, defaults to `undefined` |
|||
lower: false, // convert to lower case, defaults to `false` |
|||
strict: false, // strip special characters except replacement, defaults to `false` |
|||
locale: 'vi' // language code of the locale to use |
|||
}) |
|||
``` |
|||
|
|||
## Remove |
|||
|
|||
For example, to remove `*+~.()'"!:@` from the result slug, you can use `slugify('..', {remove: /[*+~.()'"!:@]/g})`. |
|||
|
|||
## Locales |
|||
|
|||
The main `charmap.json` file contains all known characters and their transliteration. All new characters should be added there first. In case you stumble upon a character already set in `charmap.json`, but not transliterated correctly according to your language, then you have to add those characters in `locales.json` to override the already existing transliteration in `charmap.json`, but for your locale only. |
|||
|
|||
You can get the correct language code of your language from [here](https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes). |
|||
|
|||
## Extend |
|||
|
|||
Out of the box `slugify` comes with support for a handful of Unicode symbols. For example the `☢` (radioactive) symbol is not defined in the [`charMap`][charmap] and therefore it will be stripped by default: |
|||
|
|||
```js |
|||
slugify('unicode ♥ is ☢') // unicode-love-is |
|||
``` |
|||
|
|||
However you can extend the supported symbols, or override the existing ones with your own: |
|||
|
|||
```js |
|||
slugify.extend({'☢': 'radioactive'}) |
|||
slugify('unicode ♥ is ☢') // unicode-love-is-radioactive |
|||
``` |
|||
|
|||
Keep in mind that the `extend` method extends/overrides the default `charMap` for the entire process. In case you need a fresh instance of the slugify's `charMap` object you have to clean up the module cache first: |
|||
|
|||
```js |
|||
delete require.cache[require.resolve('slugify')] |
|||
var slugify = require('slugify') |
|||
``` |
|||
|
|||
## Contribute |
|||
|
|||
1. Add chars to `charmap.json` |
|||
2. Run tests `npm test` |
|||
3. The tests will build the charmap in `index.js` and will sort the `charmap.json` |
|||
4. Commit **all** modified files |
|||
|
|||
--- |
|||
|
|||
> This module was originally a vanilla javascript port of [node-slug][node-slug].<br> |
|||
> Note that the original [slug][slug] module has been ported to vanilla javascript too.<br> |
|||
> One major difference between the two modules is that `slugify` does not depend on the external [unicode][unicode] module. |
|||
|
|||
|
|||
[npm-version]: https://img.shields.io/npm/v/slugify.svg?style=flat-square (NPM Package Version) |
|||
[travis-ci]: https://img.shields.io/travis/simov/slugify/master.svg?style=flat-square (Build Status - Travis CI) |
|||
[coveralls-status]: https://img.shields.io/coveralls/simov/slugify.svg?style=flat-square (Test Coverage - Coveralls) |
|||
|
|||
[npm]: https://www.npmjs.com/package/slugify |
|||
[travis]: https://travis-ci.org/simov/slugify |
|||
[coveralls]: https://coveralls.io/r/simov/slugify?branch=master |
|||
|
|||
[node-slug]: https://github.com/dodo/node-slug |
|||
[slug]: https://www.npmjs.com/package/slug |
|||
[unicode]: https://www.npmjs.com/package/unicode |
|||
[index]: https://github.com/simov/slugify/blob/master/index.js |
|||
[charmap]: https://github.com/simov/slugify/blob/master/config/charmap.json |
|||
@ -0,0 +1,40 @@ |
|||
{ |
|||
"name": "slugify", |
|||
"version": "1.4.6", |
|||
"description": "Slugifies a String", |
|||
"keywords": [ |
|||
"slugify", |
|||
"slug", |
|||
"url", |
|||
"urlify" |
|||
], |
|||
"license": "MIT", |
|||
"homepage": "https://github.com/simov/slugify", |
|||
"author": "Simeon Velichkov <simeonvelichkov@gmail.com> (https://simov.github.io)", |
|||
"repository": { |
|||
"type": "git", |
|||
"url": "https://github.com/simov/slugify.git" |
|||
}, |
|||
"devDependencies": { |
|||
"coveralls": "^3.1.0", |
|||
"mocha": "^7.2.0", |
|||
"nyc": "^15.1.0" |
|||
}, |
|||
"main": "./slugify.js", |
|||
"files": [ |
|||
"LICENSE", |
|||
"README.md", |
|||
"slugify.d.ts", |
|||
"slugify.js" |
|||
], |
|||
"types": "slugify.d.ts", |
|||
"scripts": { |
|||
"build": "node bin/build", |
|||
"test:ci": "npx mocha --recursive", |
|||
"test:cov": "npx nyc --reporter=lcov --reporter=text-summary mocha -- --recursive", |
|||
"test": "npm run build && npm run test:ci" |
|||
}, |
|||
"engines": { |
|||
"node": ">=8.0.0" |
|||
} |
|||
} |
|||
@ -0,0 +1,23 @@ |
|||
declare module slugify { |
|||
type ExtendArgs = { |
|||
[key: string]: any; |
|||
} |
|||
|
|||
export function extend (args: ExtendArgs): void; |
|||
} |
|||
|
|||
declare function slugify( |
|||
string: string, |
|||
options?: |
|||
| { |
|||
replacement?: string; |
|||
remove?: RegExp; |
|||
lower?: boolean; |
|||
strict?: boolean; |
|||
locale?: string; |
|||
} |
|||
| string, |
|||
|
|||
): string; |
|||
|
|||
export default slugify; |
|||
File diff suppressed because one or more lines are too long
@ -0,0 +1,17 @@ |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
using System.Text; |
|||
using System.Threading.Tasks; |
|||
using Volo.Abp.AspNetCore.Mvc.UI.Bundling; |
|||
|
|||
namespace Volo.CmsKit.Admin.Web.Bundles |
|||
{ |
|||
public class SlugifyScriptContributor : BundleContributor |
|||
{ |
|||
public override void ConfigureBundle(BundleConfigurationContext context) |
|||
{ |
|||
context.Files.Add("/libs/slugify/slugify.js"); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,79 @@ |
|||
@page |
|||
|
|||
@using Volo.CmsKit.Admin.Web.Pages.CmsKit.Contents.Components.EntityContentEditor |
|||
@using Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Pages.Shared.Components.AbpPageToolbar |
|||
@using Volo.CmsKit.Admin.Web.Pages |
|||
@using Volo.CmsKit.Admin.Web.Menus |
|||
@using Volo.CmsKit.Admin.Web.Pages.CmsKit.BlogPosts |
|||
@using Volo.CmsKit.Admin.Web.Pages.CmsKit.Tags.Components.TagEditor |
|||
@using Volo.CmsKit.Blogs |
|||
@using Volo.Abp.AspNetCore.Mvc.UI.Packages.Uppy |
|||
@using Volo.CmsKit.Admin.Web.Bundles |
|||
|
|||
@inherits CmsKitAdminPageBase |
|||
|
|||
@model CreateModel |
|||
|
|||
@{ |
|||
PageLayout.Content.Title = L["BlogPosts"].Value; |
|||
PageLayout.Content.BreadCrumb.Add(L["Menu:CMS"].Value); |
|||
PageLayout.Content.MenuItemName = CmsKitAdminMenus.BlogPosts.BlogPostsMenu; |
|||
} |
|||
|
|||
@section scripts { |
|||
<abp-script-bundle> |
|||
<abp-script type="typeof(UppyScriptContributor)" /> |
|||
<abp-script src="/Pages/CmsKit/BlogPosts/create.js" /> |
|||
<abp-script type="typeof(SlugifyScriptContributor)" /> |
|||
</abp-script-bundle> |
|||
} |
|||
|
|||
@section content_toolbar { |
|||
@await Component.InvokeAsync(typeof(AbpPageToolbarViewComponent), new { pageName = typeof(CreateModel).FullName }) |
|||
} |
|||
|
|||
<abp-card> |
|||
<abp-card-header title="@L["New"].Value"></abp-card-header> |
|||
<abp-card-body> |
|||
<div class="form-group"> |
|||
<label>@L["CoverImage"]</label> |
|||
<input type="file" id="BlogPostCoverImage" class="form-control" /> |
|||
</div> |
|||
|
|||
<abp-dynamic-form abp-model="ViewModel" asp-page="/CmsKit/BlogPosts/Create" id="form-blog-post-create"> |
|||
<div class="form-group"> |
|||
<label asp-for="ViewModel.BlogId"></label> |
|||
<select asp-for="ViewModel.BlogId" id="BlogSelectionSelect" class="form-control"></select> |
|||
<span asp-validation-for="ViewModel.BlogId"></span> |
|||
</div> |
|||
|
|||
<abp-input asp-for="ViewModel.Title" /> |
|||
|
|||
<abp-input asp-for="ViewModel.Slug" /> |
|||
|
|||
@await Component.InvokeAsync(typeof(EntityContentEditorViewComponent), new |
|||
{ |
|||
entityType = BlogPostConsts.EntityType, |
|||
displaySubmitButton = false |
|||
}) |
|||
|
|||
<abp-form-content /> |
|||
|
|||
</abp-dynamic-form> |
|||
|
|||
<div id="blog-post-tags-wrapper"> |
|||
|
|||
<hr /> |
|||
|
|||
@await Component.InvokeAsync(typeof(TagEditorViewComponent), new |
|||
{ |
|||
entityType = BlogPostConsts.EntityType, |
|||
displaySubmitButton = false |
|||
}) |
|||
</div> |
|||
|
|||
</abp-card-body> |
|||
<abp-card-footer> |
|||
<abp-button button-type="Primary" type="submit" text="@L["Submit"].Value" id="button-blog-post-create" /> |
|||
</abp-card-footer> |
|||
</abp-card> |
|||
@ -0,0 +1,63 @@ |
|||
using AutoMapper; |
|||
using Microsoft.AspNetCore.Mvc; |
|||
using Microsoft.AspNetCore.Mvc.Rendering; |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.ComponentModel.DataAnnotations; |
|||
using System.Linq; |
|||
using System.Text; |
|||
using System.Threading.Tasks; |
|||
using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form; |
|||
using Volo.Abp.Validation; |
|||
using Volo.CmsKit.Admin.Blogs; |
|||
using Volo.CmsKit.Blogs; |
|||
|
|||
namespace Volo.CmsKit.Admin.Web.Pages.CmsKit.BlogPosts |
|||
{ |
|||
public class CreateModel : CmsKitAdminPageModel |
|||
{ |
|||
protected IBlogPostAdminAppService BlogPostAdminAppService { get; } |
|||
|
|||
[BindProperty] |
|||
public CreateBlogPostViewModel ViewModel { get; set; } |
|||
|
|||
public CreateModel( |
|||
IBlogPostAdminAppService blogPostAdminAppService) |
|||
{ |
|||
BlogPostAdminAppService = blogPostAdminAppService; |
|||
} |
|||
|
|||
public async Task<IActionResult> OnPostAsync() |
|||
{ |
|||
var dto = ObjectMapper.Map<CreateBlogPostViewModel, CreateBlogPostDto>(ViewModel); |
|||
|
|||
var created = await BlogPostAdminAppService.CreateAsync(dto); |
|||
|
|||
return new OkObjectResult(created); |
|||
} |
|||
|
|||
[AutoMap(typeof(CreateBlogPostDto), ReverseMap = true)] |
|||
public class CreateBlogPostViewModel |
|||
{ |
|||
[Required] |
|||
[DynamicFormIgnore] |
|||
public Guid BlogId { get; set; } |
|||
|
|||
[Required] |
|||
[DynamicMaxLength(typeof(BlogPostConsts), nameof(BlogPostConsts.MaxTitleLength))] |
|||
[DynamicFormIgnore] |
|||
public string Title { get; set; } |
|||
|
|||
[Required] |
|||
[DynamicStringLength( |
|||
typeof(BlogPostConsts), |
|||
nameof(BlogPostConsts.MaxSlugLength), |
|||
nameof(BlogPostConsts.MinSlugLength))] |
|||
[DynamicFormIgnore] |
|||
public string Slug { get; set; } |
|||
|
|||
[DynamicMaxLength(typeof(BlogPostConsts), nameof(BlogPostConsts.MaxShortDescriptionLength))] |
|||
public string ShortDescription { get; set; } |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,33 @@ |
|||
@page |
|||
|
|||
@using Volo.CmsKit.Admin.Web.Pages.CmsKit.BlogPosts |
|||
@using Volo.CmsKit.Admin.Web.Pages |
|||
@using Volo.CmsKit.Admin.Web.Menus |
|||
@using Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Pages.Shared.Components.AbpPageToolbar |
|||
|
|||
@inherits CmsKitAdminPageBase |
|||
|
|||
@model IndexModel |
|||
|
|||
@{ |
|||
PageLayout.Content.Title = L["BlogPosts"].Value; |
|||
PageLayout.Content.BreadCrumb.Add(L["Menu:CMS"].Value); |
|||
PageLayout.Content.MenuItemName = CmsKitAdminMenus.BlogPosts.BlogPostsMenu; |
|||
} |
|||
|
|||
@section scripts { |
|||
<abp-script src="/Pages/CmsKit/BlogPosts/index.js" /> |
|||
} |
|||
|
|||
|
|||
@section content_toolbar { |
|||
@await Component.InvokeAsync(typeof(AbpPageToolbarViewComponent), new { pageName = typeof(IndexModel).FullName }) |
|||
} |
|||
|
|||
<div id="CmsKitBlogPostsWrapper"> |
|||
<abp-card> |
|||
<abp-card-body> |
|||
<abp-table striped-rows="true" id="BlogPostsTable" class="nowrap"></abp-table> |
|||
</abp-card-body> |
|||
</abp-card> |
|||
</div> |
|||
@ -0,0 +1,7 @@ |
|||
namespace Volo.CmsKit.Admin.Web.Pages.CmsKit.BlogPosts |
|||
{ |
|||
public class IndexModel : CmsKitAdminPageModel |
|||
{ |
|||
|
|||
} |
|||
} |
|||
@ -0,0 +1,77 @@ |
|||
@page "{Id}" |
|||
|
|||
@using Volo.CmsKit.Blogs |
|||
@using Volo.CmsKit.Admin.Web.Pages |
|||
@using Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Pages.Shared.Components.AbpPageToolbar |
|||
@using Volo.CmsKit.Admin.Web.Pages.CmsKit.Contents.Components.EntityContentEditor |
|||
@using Volo.CmsKit.Admin.Web.Menus |
|||
@using Volo.CmsKit.Admin.Web.Pages.CmsKit.BlogPosts |
|||
@using Volo.CmsKit.Admin.Web.Pages.CmsKit.Tags.Components.TagEditor |
|||
@using Volo.Abp.AspNetCore.Mvc.UI.Packages.Uppy |
|||
@using Volo.CmsKit.Admin.Web.Bundles |
|||
|
|||
@inherits CmsKitAdminPageBase |
|||
|
|||
@model UpdateModel |
|||
|
|||
@{ |
|||
PageLayout.Content.Title = L["BlogPosts"].Value; |
|||
PageLayout.Content.BreadCrumb.Add(L["Menu:CMS"].Value); |
|||
PageLayout.Content.MenuItemName = CmsKitAdminMenus.BlogPosts.BlogPostsMenu; |
|||
} |
|||
|
|||
@section scripts { |
|||
<abp-script-bundle> |
|||
<abp-script type="typeof(UppyScriptContributor)" /> |
|||
<abp-script src="/Pages/CmsKit/BlogPosts/update.js" /> |
|||
<abp-script type="typeof(SlugifyScriptContributor)" /> |
|||
</abp-script-bundle> |
|||
} |
|||
|
|||
@section content_toolbar { |
|||
@await Component.InvokeAsync(typeof(AbpPageToolbarViewComponent), new { pageName = typeof(UpdateModel).FullName }) |
|||
} |
|||
|
|||
<abp-card> |
|||
<abp-card-header title="@L["Update"].Value"></abp-card-header> |
|||
<abp-card-body> |
|||
|
|||
<div class="form-group"> |
|||
<img height="120" src="/api/cms-kit-admin/blogs/blog-posts/@Model.Id/cover-image" /> |
|||
<label>@L["CoverImage"]</label> |
|||
<input type="file" id="BlogPostCoverImage" class="form-control" /> |
|||
</div> |
|||
|
|||
<abp-dynamic-form abp-model="ViewModel" asp-page="/CmsKit/BlogPosts/Update" id="form-blog-post-update"> |
|||
<abp-input asp-for="Id" /> |
|||
|
|||
<abp-input asp-for="ViewModel.Title" /> |
|||
|
|||
<abp-input asp-for="ViewModel.Slug" /> |
|||
|
|||
@await Component.InvokeAsync(typeof(EntityContentEditorViewComponent), new |
|||
{ |
|||
entityType = BlogPostConsts.EntityType, |
|||
entityId = Model.Id.ToString(), |
|||
displaySubmitButton = false |
|||
}) |
|||
|
|||
<abp-form-content /> |
|||
</abp-dynamic-form> |
|||
|
|||
@if (Model.TagsFeature?.IsEnabled == true) |
|||
{ |
|||
<hr /> |
|||
|
|||
@await Component.InvokeAsync(typeof(TagEditorViewComponent), new |
|||
{ |
|||
entityType = BlogPostConsts.EntityType, |
|||
entityId = Model.Id.ToString(), |
|||
displaySubmitButton = false |
|||
}) |
|||
} |
|||
</abp-card-body> |
|||
<abp-card-footer> |
|||
<abp-button button-type="Primary" type="submit" text="@L["Submit"].Value" id="button-blog-post-update" /> |
|||
</abp-card-footer> |
|||
</abp-card> |
|||
@ -0,0 +1,77 @@ |
|||
using AutoMapper; |
|||
using Microsoft.AspNetCore.Mvc; |
|||
using Microsoft.AspNetCore.Mvc.Rendering; |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.ComponentModel.DataAnnotations; |
|||
using System.Linq; |
|||
using System.Text; |
|||
using System.Threading.Tasks; |
|||
using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form; |
|||
using Volo.Abp.Validation; |
|||
using Volo.CmsKit.Admin.Blogs; |
|||
using Volo.CmsKit.Blogs; |
|||
|
|||
namespace Volo.CmsKit.Admin.Web.Pages.CmsKit.BlogPosts |
|||
{ |
|||
public class UpdateModel : CmsKitAdminPageModel |
|||
{ |
|||
protected IBlogPostAdminAppService BlogPostAdminAppService { get; } |
|||
protected IBlogFeatureAppService BlogFeatureAppService { get; } |
|||
|
|||
[BindProperty] |
|||
public virtual UpdateBlogPostViewModel ViewModel { get; set; } |
|||
|
|||
[HiddenInput] |
|||
[BindProperty(SupportsGet = true)] |
|||
public virtual Guid Id { get; set; } |
|||
|
|||
public virtual BlogFeatureDto TagsFeature { get; protected set; } |
|||
|
|||
public UpdateModel( |
|||
IBlogPostAdminAppService blogPostAdminAppService, |
|||
IBlogFeatureAppService blogFeatureAppService) |
|||
{ |
|||
BlogPostAdminAppService = blogPostAdminAppService; |
|||
BlogFeatureAppService = blogFeatureAppService; |
|||
} |
|||
|
|||
public virtual async Task OnGetAsync() |
|||
{ |
|||
var blogPost = await BlogPostAdminAppService.GetAsync(Id); |
|||
|
|||
ViewModel = ObjectMapper.Map<BlogPostDto, UpdateBlogPostViewModel>(blogPost); |
|||
|
|||
TagsFeature = await BlogFeatureAppService.GetOrDefaultAsync(blogPost.BlogId, GlobalFeatures.TagsFeature.Name); |
|||
} |
|||
|
|||
public virtual async Task<IActionResult> OnPostAsync() |
|||
{ |
|||
var dto = ObjectMapper.Map<UpdateBlogPostViewModel, UpdateBlogPostDto>(ViewModel); |
|||
|
|||
await BlogPostAdminAppService.UpdateAsync(Id, dto); |
|||
|
|||
return NoContent(); |
|||
} |
|||
|
|||
[AutoMap(typeof(BlogPostDto))] |
|||
[AutoMap(typeof(UpdateBlogPostDto), ReverseMap = true)] |
|||
public class UpdateBlogPostViewModel |
|||
{ |
|||
[DynamicMaxLength(typeof(BlogPostConsts), nameof(BlogPostConsts.MaxTitleLength))] |
|||
[Required] |
|||
[DynamicFormIgnore] |
|||
public string Title { get; set; } |
|||
|
|||
[DynamicStringLength(typeof(BlogPostConsts), nameof(BlogPostConsts.MaxSlugLength), nameof(BlogPostConsts.MinSlugLength))] |
|||
[Required] |
|||
[DisplayOrder(10000)] |
|||
[DynamicFormIgnore] |
|||
public string Slug { get; set; } |
|||
|
|||
[DynamicMaxLength(typeof(BlogPostConsts), nameof(BlogPostConsts.MaxShortDescriptionLength))] |
|||
[DisplayOrder(10001)] |
|||
public string ShortDescription { get; set; } |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,212 @@ |
|||
$(function () { |
|||
|
|||
var l = abp.localization.getResource("CmsKit"); |
|||
|
|||
var $selectBlog = $('#BlogSelectionSelect'); |
|||
var $formCreate = $('#form-blog-post-create'); |
|||
var $title = $('#ViewModel_Title'); |
|||
var $shortDescription = $('#ViewModel_ShortDescription'); |
|||
var $url = $('#ViewModel_Slug'); |
|||
var $buttonSubmit = $('#button-blog-post-create'); |
|||
var $pageContentInput = $('#ViewModel_Value'); |
|||
var $tagsInput = $('.tag-editor-form input[name=tags]'); |
|||
var $fileInput = $('#BlogPostCoverImage'); |
|||
var $tagsWrapper = $('#blog-post-tags-wrapper'); |
|||
|
|||
var UPPY_UPLOAD_ENDPOINT = "/api/cms-kit-admin/blogs/blog-posts/{0}/cover-image"; |
|||
var UPPY_FILE_ID = "uppy-upload-file"; |
|||
|
|||
var isTagsEnabled = true; |
|||
|
|||
$formCreate.data('validator').settings.ignore = ":hidden, [contenteditable='true']:not([name]), .tui-popup-wrapper"; |
|||
|
|||
function initSelectBlog() { |
|||
$selectBlog.data('autocompleteApiUrl', '/api/cms-kit-admin/blogs'); |
|||
$selectBlog.data('autocompleteDisplayProperty', 'name'); |
|||
$selectBlog.data('autocompleteValueProperty', 'id'); |
|||
$selectBlog.data('autocompleteItemsProperty', 'items'); |
|||
$selectBlog.data('autocompleteFilterParamName', 'filter'); |
|||
|
|||
abp.dom.initializers.initializeAutocompleteSelects($selectBlog); |
|||
} |
|||
|
|||
initSelectBlog(); |
|||
|
|||
$formCreate.on('submit', function (e) { |
|||
e.preventDefault(); |
|||
|
|||
if ($formCreate.valid()) { |
|||
|
|||
abp.ui.setBusy(); |
|||
|
|||
$formCreate.ajaxSubmit({ |
|||
success: function (result) { |
|||
submitEntityContent(result.id); |
|||
}, |
|||
error: function (result) { |
|||
abp.notify.error(result.responseJSON.error.message); |
|||
abp.ui.clearBusy(); |
|||
} |
|||
}); |
|||
} |
|||
}); |
|||
|
|||
$buttonSubmit.click(function (e) { |
|||
e.preventDefault(); |
|||
$formCreate.submit(); |
|||
}); |
|||
|
|||
function submitEntityContent(blogPostId) { |
|||
volo.cmsKit.admin.contents.contentAdmin |
|||
.create( |
|||
{ |
|||
entityType: 'BlogPost', |
|||
entityId: blogPostId, |
|||
value: $pageContentInput.val() |
|||
}) |
|||
.then(function (result) { |
|||
if (isTagsEnabled) { |
|||
submitEntityTags(blogPostId) |
|||
} |
|||
else { |
|||
submitCoverImage(blogPostId); |
|||
} |
|||
}); |
|||
} |
|||
|
|||
function submitEntityTags(blogPostId) { |
|||
|
|||
var tags = $tagsInput.val().split(","); |
|||
|
|||
volo.cmsKit.admin.tags.entityTagAdmin |
|||
.setEntityTags({ |
|||
entityType: 'BlogPost', |
|||
entityId: blogPostId, |
|||
tags: tags |
|||
}) |
|||
.then(function (result) { |
|||
submitCoverImage(blogPostId); |
|||
}); |
|||
} |
|||
|
|||
function getUppyHeaders() { |
|||
var headers = {}; |
|||
headers[abp.security.antiForgery.tokenHeaderName] = abp.security.antiForgery.getToken(); |
|||
|
|||
return headers; |
|||
} |
|||
|
|||
function submitCoverImage(blogPostId) { |
|||
var UPPY_OPTIONS = { |
|||
endpoint: UPPY_UPLOAD_ENDPOINT.replace("{0}", blogPostId), |
|||
formData: true, |
|||
fieldName: "file", |
|||
method: "post", |
|||
headers: getUppyHeaders() |
|||
}; |
|||
|
|||
var UPPY = Uppy.Core().use(Uppy.XHRUpload, UPPY_OPTIONS); |
|||
|
|||
UPPY.reset(); |
|||
|
|||
var file = $fileInput[0].files[0]; |
|||
|
|||
if (file) { |
|||
|
|||
UPPY.addFile({ |
|||
id: UPPY_FILE_ID, |
|||
name: file.name, // file name
|
|||
type: file.type, // file type
|
|||
data: file, // file
|
|||
}); |
|||
|
|||
UPPY.upload().then((result) => { |
|||
if (result.failed.length > 0) { |
|||
abp.message.error(l("UploadFailedMessage")); |
|||
} else { |
|||
finishSaving(); |
|||
} |
|||
}); |
|||
} |
|||
else { |
|||
finishSaving(); |
|||
} |
|||
} |
|||
|
|||
function finishSaving() { |
|||
abp.notify.success(l('SuccessfullySaved')); |
|||
abp.ui.clearBusy(); |
|||
location.href = "../BlogPosts"; |
|||
} |
|||
|
|||
var urlEdited = false; |
|||
var reflectedChange = false; |
|||
|
|||
$url.on('change', function () { |
|||
reflectUrlChanges(); |
|||
}); |
|||
|
|||
$title.on('keyup paste', function () { |
|||
reflectUrlChanges(); |
|||
}); |
|||
|
|||
function reflectUrlChanges() { |
|||
var title = $title.val().toLocaleLowerCase(); |
|||
|
|||
if (urlEdited) { |
|||
title = $url.val(); |
|||
} |
|||
|
|||
var slugified = slugify(title, { |
|||
lower: true |
|||
}); |
|||
|
|||
if (slugified != $url.val()) { |
|||
reflectedChange = true; |
|||
|
|||
$url.val(slugified); |
|||
|
|||
reflectedChange = false; |
|||
} |
|||
} |
|||
|
|||
$url.change(function () { |
|||
if (!reflectedChange) { |
|||
urlEdited = true; |
|||
} |
|||
}); |
|||
|
|||
var shorDescriptionEdited = false; |
|||
$pageContentInput.on('change', function () { |
|||
if (shorDescriptionEdited) { |
|||
return; |
|||
} |
|||
|
|||
var htmlValue = $pageContentInput.val(); |
|||
|
|||
var plainValue = jQuery('<div>').html(htmlValue).text().replace(/\n/g, ' ').substring(0, 120); |
|||
|
|||
$shortDescription.val(plainValue); |
|||
}); |
|||
|
|||
$shortDescription.on('change', function () { |
|||
shorDescriptionEdited = true; |
|||
}); |
|||
|
|||
$selectBlog.on('change', function () { |
|||
var blogId = $selectBlog.val(); |
|||
volo.cmsKit.blogs.blogFeature |
|||
.getOrDefault(blogId, 'CmsKit.Tags') |
|||
.then(function (result) { |
|||
if (result) { |
|||
isTagsEnabled = result.isEnabled == true |
|||
if (isTagsEnabled === true) { |
|||
$tagsWrapper.removeClass('d-none'); |
|||
} |
|||
else { |
|||
$tagsWrapper.addClass('d-none'); |
|||
} |
|||
} |
|||
}); |
|||
}); |
|||
}); |
|||
@ -0,0 +1,68 @@ |
|||
|
|||
$(function () { |
|||
var l = abp.localization.getResource("CmsKit"); |
|||
|
|||
var blogsService = volo.cmsKit.admin.blogs.blogPostAdmin; |
|||
|
|||
var $blogPostWrapper = $('#CmsKitBlogPostsWrapper'); |
|||
|
|||
var dataTable = $("#BlogPostsTable").DataTable(abp.libs.datatables.normalizeConfiguration({ |
|||
processing: true, |
|||
serverSide: true, |
|||
paging: true, |
|||
searching: false, |
|||
autoWidth: false, |
|||
scrollCollapse: true, |
|||
scrollX: true, |
|||
ordering: true, |
|||
order: [[1, "desc"]], |
|||
ajax: abp.libs.datatables.createAjax(blogsService.getList), |
|||
columnDefs: [ |
|||
{ |
|||
title: l("Details"), |
|||
targets: 0, |
|||
rowAction: { |
|||
items: [ |
|||
{ |
|||
text: l('Edit'), |
|||
visible: abp.auth.isGranted('CmsKit.Blogs.Update'), |
|||
action: function (data) { |
|||
location.href = "/CmsKit/BlogPosts/Update/" + data.record.id |
|||
} |
|||
}, |
|||
{ |
|||
text: l('Delete'), |
|||
visible: abp.auth.isGranted('CmsKit.Blogs.Delete'), |
|||
confirmMessage: function (data) { |
|||
return l("BlogPostDeletionConfirmationMessage", data.record.title) |
|||
}, |
|||
action: function (data) { |
|||
blogsService |
|||
.delete(data.record.id) |
|||
.then(function () { |
|||
abp.notify.info(l("SuccessfullyDeleted")); |
|||
dataTable.ajax.reload(); |
|||
}); |
|||
} |
|||
} |
|||
] |
|||
} |
|||
}, |
|||
{ |
|||
title: l("Title"), |
|||
orderable: true, |
|||
data: "title" |
|||
}, |
|||
{ |
|||
title: l("Slug"), |
|||
orderable: true, |
|||
data: "slug" |
|||
} |
|||
] |
|||
})); |
|||
|
|||
$('#AbpContentToolbar button[name=CreateBlogPost]').on('click', function (e) { |
|||
e.preventDefault(); |
|||
window.location.href = "/CmsKit/BlogPosts/Create" |
|||
}); |
|||
}); |
|||
@ -0,0 +1,180 @@ |
|||
$(function () { |
|||
|
|||
var l = abp.localization.getResource("CmsKit"); |
|||
|
|||
var $selectBlog = $('#BlogSelectionSelect'); |
|||
var $formUpdate = $('#form-blog-post-update'); |
|||
var $title = $('#ViewModel_Title'); |
|||
var $titleClone = $('#title-clone'); |
|||
var $slug = $('#ViewModel_Slug'); |
|||
var $buttonSubmit = $('#button-blog-post-update'); |
|||
var $contentValueInput = $('#ViewModel_Value'); |
|||
var $blogPostIdInput = $('#Id'); |
|||
var $contentIdInput = $('#ViewModel_Id'); |
|||
var $tagsInput = $('.tag-editor-form input[name=tags]'); |
|||
var $fileInput = $('#BlogPostCoverImage'); |
|||
|
|||
var UPPY_UPLOAD_ENDPOINT = "/api/cms-kit-admin/blogs/blog-posts/{0}/cover-image"; |
|||
var UPPY_FILE_ID = "uppy-upload-file"; |
|||
|
|||
$formUpdate.data('validator').settings.ignore = ":hidden, [contenteditable='true']:not([name]), .tui-popup-wrapper"; |
|||
|
|||
function initSelectBlog() { |
|||
$selectBlog.data('autocompleteApiUrl', '/api/cms-kit-admin/blogs/blogs'); |
|||
$selectBlog.data('autocompleteDisplayProperty', 'name'); |
|||
$selectBlog.data('autocompleteValueProperty', 'id'); |
|||
$selectBlog.data('autocompleteItemsProperty', 'items'); |
|||
$selectBlog.data('autocompleteFilterParamName', 'filter'); |
|||
|
|||
abp.dom.initializers.initializeAutocompleteSelects($selectBlog); |
|||
} |
|||
|
|||
initSelectBlog(); |
|||
|
|||
$formUpdate.on('submit', function (e) { |
|||
e.preventDefault(); |
|||
|
|||
if ($formUpdate.valid()) { |
|||
|
|||
abp.ui.setBusy(); |
|||
|
|||
$formUpdate.ajaxSubmit({ |
|||
success: function (result) { |
|||
submitEntityContent(); |
|||
}, |
|||
error: function (result) { |
|||
abp.ui.clearBusy(); abp.notify.error(result.responseJSON.error.message); |
|||
} |
|||
}); |
|||
} |
|||
}); |
|||
|
|||
$buttonSubmit.click(function (e) { |
|||
e.preventDefault(); |
|||
$formUpdate.submit(); |
|||
}); |
|||
|
|||
function submitEntityContent() { |
|||
|
|||
var contentId = $contentIdInput.val(); |
|||
var blogPostId = $blogPostIdInput.val(); |
|||
var contentValue = $contentValueInput.val(); |
|||
|
|||
if (contentId) { |
|||
volo.cmsKit.admin.contents.contentAdmin |
|||
.update(contentId, |
|||
{ |
|||
value: contentValue |
|||
}) |
|||
.then(function (result) { |
|||
entityContentCallback(blogPostId); |
|||
}); |
|||
} |
|||
else { |
|||
volo.cmsKit.admin.contents.contentAdmin |
|||
.create({ |
|||
entityType: 'BlogPost', |
|||
entityId: blogPostId, |
|||
value: contentValue |
|||
}) |
|||
.then(function (result) { |
|||
entityContentCallback(blogPostId); |
|||
}); |
|||
} |
|||
} |
|||
|
|||
function entityContentCallback(blogPostId) { |
|||
if ($tagsInput.val()) { |
|||
submitEntityTags(blogPostId); |
|||
} |
|||
else { |
|||
submitCoverImage(blogPostId); |
|||
} |
|||
} |
|||
|
|||
function submitEntityTags(blogPostId) { |
|||
|
|||
var tags = $tagsInput.val().split(","); |
|||
|
|||
volo.cmsKit.admin.tags.entityTagAdmin |
|||
.setEntityTags({ |
|||
entityType: 'BlogPost', |
|||
entityId: blogPostId, |
|||
tags: tags |
|||
}) |
|||
.then(function (result) { |
|||
submitCoverImage(blogPostId); |
|||
}); |
|||
} |
|||
|
|||
function getUppyHeaders() { |
|||
var headers = {}; |
|||
headers[abp.security.antiForgery.tokenHeaderName] = abp.security.antiForgery.getToken(); |
|||
|
|||
return headers; |
|||
} |
|||
|
|||
function submitCoverImage(blogPostId) { |
|||
var UPPY_OPTIONS = { |
|||
endpoint: UPPY_UPLOAD_ENDPOINT.replace("{0}", blogPostId), |
|||
formData: true, |
|||
fieldName: "file", |
|||
method: "post", |
|||
headers: getUppyHeaders() |
|||
}; |
|||
|
|||
var UPPY = Uppy.Core().use(Uppy.XHRUpload, UPPY_OPTIONS); |
|||
|
|||
UPPY.reset(); |
|||
|
|||
var file = $fileInput[0].files[0]; |
|||
|
|||
if (file) { |
|||
|
|||
UPPY.addFile({ |
|||
id: UPPY_FILE_ID, |
|||
name: file.name, // file name
|
|||
type: file.type, // file type
|
|||
data: file, // file
|
|||
}); |
|||
|
|||
UPPY.upload().then((result) => { |
|||
if (result.failed.length > 0) { |
|||
abp.message.error(l("UploadFailedMessage")); |
|||
} else { |
|||
finishSaving(); |
|||
} |
|||
}); |
|||
} |
|||
else { |
|||
finishSaving(); |
|||
} |
|||
} |
|||
|
|||
function finishSaving(result) { |
|||
abp.notify.success(l('SuccessfullySaved')); |
|||
abp.ui.clearBusy(); |
|||
location.href = "../BlogPosts/"; |
|||
} |
|||
|
|||
$titleClone.on('change paste keyup', function () { |
|||
$title.val($titleClone.val()); |
|||
}); |
|||
|
|||
$slug.on('change', function () { |
|||
reflectUrlChanges(); |
|||
}); |
|||
|
|||
function reflectUrlChanges() { |
|||
|
|||
var title = $slug.val(); |
|||
|
|||
var slugified = slugify(title); |
|||
|
|||
if (slugified != title) { |
|||
$slug.val(slugified, { |
|||
lower: true |
|||
}); |
|||
} |
|||
} |
|||
}); |
|||
@ -0,0 +1,23 @@ |
|||
@page |
|||
|
|||
@using Volo.CmsKit.Admin.Web.Pages.CmsKit.Blogs |
|||
@using Volo.CmsKit.Admin.Web.Pages |
|||
@using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Modal |
|||
|
|||
@inherits CmsKitAdminPageBase |
|||
|
|||
@model CreateModalModel |
|||
|
|||
@{ |
|||
Layout = null; |
|||
} |
|||
|
|||
<abp-dynamic-form abp-model="ViewModel" asp-page="/CmsKit/Blogs/CreateModal"> |
|||
<abp-modal> |
|||
<abp-modal-header title="@L["New"].Value"></abp-modal-header> |
|||
<abp-modal-body> |
|||
<abp-form-content /> |
|||
</abp-modal-body> |
|||
<abp-modal-footer buttons="@(AbpModalButtons.Cancel | AbpModalButtons.Save)"></abp-modal-footer> |
|||
</abp-modal> |
|||
</abp-dynamic-form> |
|||
@ -0,0 +1,44 @@ |
|||
using AutoMapper; |
|||
using Microsoft.AspNetCore.Mvc; |
|||
using System.ComponentModel.DataAnnotations; |
|||
using System.Threading.Tasks; |
|||
using Volo.Abp.Validation; |
|||
using Volo.CmsKit.Admin.Blogs; |
|||
using Volo.CmsKit.Blogs; |
|||
|
|||
namespace Volo.CmsKit.Admin.Web.Pages.CmsKit.Blogs |
|||
{ |
|||
public class CreateModalModel : CmsKitAdminPageModel |
|||
{ |
|||
protected IBlogAdminAppService BlogAdminAppService { get; } |
|||
|
|||
[BindProperty] |
|||
public CreateBlogViewModel ViewModel { get; set; } |
|||
|
|||
public CreateModalModel(IBlogAdminAppService blogAdminAppService) |
|||
{ |
|||
BlogAdminAppService = blogAdminAppService; |
|||
} |
|||
|
|||
public async Task<IActionResult> OnPostAsync() |
|||
{ |
|||
var dto = ObjectMapper.Map<CreateBlogViewModel, CreateBlogDto>(ViewModel); |
|||
|
|||
await BlogAdminAppService.CreateAsync(dto); |
|||
|
|||
return NoContent(); |
|||
} |
|||
|
|||
[AutoMap(typeof(CreateBlogDto), ReverseMap = true)] |
|||
public class CreateBlogViewModel |
|||
{ |
|||
[Required] |
|||
[DynamicMaxLength(typeof(BlogConsts), nameof(BlogConsts.MaxNameLength))] |
|||
public string Name { get; set; } |
|||
|
|||
[DynamicMaxLength(typeof(BlogConsts), nameof(BlogConsts.MaxSlugLength))] |
|||
[Required] |
|||
public string Slug { get; set; } |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,44 @@ |
|||
@page |
|||
|
|||
@using Volo.CmsKit.Admin.Web.Pages.CmsKit.Blogs |
|||
@using Volo.CmsKit.Admin.Web.Pages |
|||
@using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Modal |
|||
|
|||
@inherits CmsKitAdminPageBase |
|||
|
|||
@model FeaturesModalModel |
|||
|
|||
@{ |
|||
Layout = null; |
|||
} |
|||
|
|||
<form action="/CmsKit/Blogs/FeaturesModal"> |
|||
<abp-modal> |
|||
<abp-modal-header title="@L["Features"].Value"></abp-modal-header> |
|||
<abp-modal-body> |
|||
<abp-input asp-for="BlogId"></abp-input> |
|||
@for (int i = 0; i < Model.Items.Count; i++) |
|||
{ |
|||
<div class="form-group"> |
|||
|
|||
@if (Model.Items[i].IsAvailable) |
|||
{ |
|||
<abp-input asp-for="Items[i].IsEnabled" |
|||
label="@L[Model.Items[i].FeatureName]" /> |
|||
} |
|||
else |
|||
{ |
|||
<div data-toggle="tooltip" title="@L["BlogFeatureNotAvailable"]"> |
|||
<abp-input asp-for="Items[i].IsEnabled" |
|||
label="@L[Model.Items[i].FeatureName]" |
|||
disabled="true" /> |
|||
</div> |
|||
} |
|||
<abp-input asp-for="Items[i].FeatureName" /> |
|||
</div> |
|||
} |
|||
|
|||
</abp-modal-body> |
|||
<abp-modal-footer buttons="@(AbpModalButtons.Close | AbpModalButtons.Save)"></abp-modal-footer> |
|||
</abp-modal> |
|||
</form> |
|||
@ -0,0 +1,77 @@ |
|||
using AutoMapper; |
|||
using Microsoft.AspNetCore.Mvc; |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
using System.Text; |
|||
using System.Threading.Tasks; |
|||
using Volo.Abp.GlobalFeatures; |
|||
using Volo.CmsKit.Admin.Blogs; |
|||
using Volo.CmsKit.Admin.Web.Pages; |
|||
using Volo.CmsKit.Blogs; |
|||
|
|||
namespace Volo.CmsKit.Admin.Web.Pages.CmsKit.Blogs |
|||
{ |
|||
public class FeaturesModalModel : CmsKitAdminPageModel |
|||
{ |
|||
[BindProperty(SupportsGet = true)] |
|||
[HiddenInput] |
|||
public Guid BlogId { get; set; } |
|||
|
|||
[BindProperty] |
|||
public List<BlogFeatureViewModel> Items { get; set; } |
|||
|
|||
protected IBlogFeatureAdminAppService BlogFeatureAdminAppService { get; } |
|||
|
|||
public FeaturesModalModel(IBlogFeatureAdminAppService blogFeatureAdminAppService) |
|||
{ |
|||
BlogFeatureAdminAppService = blogFeatureAdminAppService; |
|||
} |
|||
|
|||
public async Task OnGetAsync() |
|||
{ |
|||
var blogFeatureDtos = await BlogFeatureAdminAppService.GetListAsync(BlogId); |
|||
|
|||
Items = ObjectMapper.Map<List<BlogFeatureDto>, List<BlogFeatureViewModel>>(blogFeatureDtos); |
|||
} |
|||
|
|||
public async Task<IActionResult> OnPostAsync() |
|||
{ |
|||
var dtos = ObjectMapper.Map<List<BlogFeatureViewModel>, List<BlogFeatureInputDto>>(Items); |
|||
|
|||
foreach (var item in dtos) |
|||
{ |
|||
await BlogFeatureAdminAppService.SetAsync(BlogId, item); |
|||
} |
|||
|
|||
return NoContent(); |
|||
} |
|||
|
|||
[AutoMap(typeof(BlogFeatureDto), ReverseMap = true)] |
|||
[AutoMap(typeof(BlogFeatureInputDto), ReverseMap = true)] |
|||
public class BlogFeatureViewModel |
|||
{ |
|||
private string featureName; |
|||
[HiddenInput] |
|||
public string FeatureName { get => featureName; set => SetFeatureName(value); } |
|||
|
|||
public bool IsEnabled { get; set; } |
|||
|
|||
public bool IsAvailable { get; private set; } |
|||
|
|||
private void SetFeatureName(string value) |
|||
{ |
|||
featureName = value; |
|||
|
|||
IsAvailable = GlobalFeatureManager.Instance.Modules.CmsKit().GetFeatures().Any(a => a.FeatureName == FeatureName) ? |
|||
GlobalFeatureManager.Instance.IsEnabled(FeatureName) : |
|||
true; |
|||
|
|||
if (!IsAvailable) |
|||
{ |
|||
IsEnabled = false; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,38 @@ |
|||
@page |
|||
|
|||
@using Volo.CmsKit.Admin.Web.Pages.CmsKit.Blogs |
|||
@using Volo.CmsKit.Admin.Web.Pages |
|||
@using Volo.CmsKit.Admin.Web.Menus |
|||
@using Volo.CmsKit.Admin.Web.Bundles |
|||
@using Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Pages.Shared.Components.AbpPageToolbar |
|||
|
|||
@inherits CmsKitAdminPageBase |
|||
|
|||
@model IndexModel |
|||
|
|||
@{ |
|||
PageLayout.Content.Title = L["Blogs"].Value; |
|||
PageLayout.Content.BreadCrumb.Add(L["Menu:CMS"].Value); |
|||
PageLayout.Content.MenuItemName = CmsKitAdminMenus.Blogs.BlogsMenu; |
|||
} |
|||
|
|||
@section scripts { |
|||
<abp-script-bundle> |
|||
<abp-script src="/Pages/CmsKit/Blogs/index.js" /> |
|||
<abp-script src="/Pages/CmsKit/Blogs/createModal.js" /> |
|||
<abp-script src="/Pages/CmsKit/Blogs/updateModal.js" /> |
|||
<abp-script type="typeof(SlugifyScriptContributor)"/> |
|||
</abp-script-bundle> |
|||
} |
|||
|
|||
@section content_toolbar { |
|||
@await Component.InvokeAsync(typeof(AbpPageToolbarViewComponent), new { pageName = typeof(IndexModel).FullName }) |
|||
} |
|||
|
|||
<div id="CmsKitBlogsWrapper"> |
|||
<abp-card> |
|||
<abp-card-body> |
|||
<abp-table striped-rows="true" id="BlogsTable" class="nowrap"></abp-table> |
|||
</abp-card-body> |
|||
</abp-card> |
|||
</div> |
|||
@ -0,0 +1,7 @@ |
|||
namespace Volo.CmsKit.Admin.Web.Pages.CmsKit.Blogs |
|||
{ |
|||
public class IndexModel : CmsKitAdminPageModel |
|||
{ |
|||
|
|||
} |
|||
} |
|||
@ -0,0 +1,23 @@ |
|||
@page |
|||
@using Volo.CmsKit.Admin.Web.Pages |
|||
@using Volo.CmsKit.Admin.Web.Pages.CmsKit.Blogs |
|||
@using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Modal |
|||
|
|||
@inherits CmsKitAdminPageBase |
|||
|
|||
@model UpdateModalModel |
|||
|
|||
@{ |
|||
Layout = null; |
|||
} |
|||
|
|||
<abp-dynamic-form abp-model="ViewModel" asp-page="/CmsKit/Blogs/UpdateModal"> |
|||
<abp-modal> |
|||
<abp-modal-header title="@L["Update"].Value"></abp-modal-header> |
|||
<abp-modal-body> |
|||
<abp-input asp-for="Id" /> |
|||
<abp-form-content /> |
|||
</abp-modal-body> |
|||
<abp-modal-footer buttons="@(AbpModalButtons.Cancel|AbpModalButtons.Save)"></abp-modal-footer> |
|||
</abp-modal> |
|||
</abp-dynamic-form> |
|||
@ -0,0 +1,61 @@ |
|||
using AutoMapper; |
|||
using Microsoft.AspNetCore.Mvc; |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.ComponentModel.DataAnnotations; |
|||
using System.Linq; |
|||
using System.Runtime.CompilerServices; |
|||
using System.Text; |
|||
using System.Threading.Tasks; |
|||
using Volo.Abp.Validation; |
|||
using Volo.CmsKit.Admin.Blogs; |
|||
using Volo.CmsKit.Blogs; |
|||
|
|||
namespace Volo.CmsKit.Admin.Web.Pages.CmsKit.Blogs |
|||
{ |
|||
public class UpdateModalModel : CmsKitAdminPageModel |
|||
{ |
|||
protected IBlogAdminAppService BlogAdminAppService { get; } |
|||
|
|||
[HiddenInput] |
|||
[BindProperty(SupportsGet = true)] |
|||
public Guid Id { get; set; } |
|||
|
|||
[BindProperty] |
|||
public UpdateBlogViewModel ViewModel { get; set; } |
|||
|
|||
public UpdateModalModel(IBlogAdminAppService blogAdminAppService) |
|||
{ |
|||
BlogAdminAppService = blogAdminAppService; |
|||
} |
|||
|
|||
public async Task OnGetAsync() |
|||
{ |
|||
var blog = await BlogAdminAppService.GetAsync(Id); |
|||
|
|||
ViewModel = ObjectMapper.Map<BlogDto, UpdateBlogViewModel>(blog); |
|||
} |
|||
|
|||
public async Task<IActionResult> OnPostAsync() |
|||
{ |
|||
var dto = ObjectMapper.Map<UpdateBlogViewModel, UpdateBlogDto>(ViewModel); |
|||
|
|||
await BlogAdminAppService.UpdateAsync(Id, dto); |
|||
|
|||
return NoContent(); |
|||
} |
|||
|
|||
[AutoMap(typeof(BlogDto))] |
|||
[AutoMap(typeof(UpdateBlogDto), ReverseMap = true)] |
|||
public class UpdateBlogViewModel |
|||
{ |
|||
[Required] |
|||
[DynamicMaxLength(typeof(BlogConsts), nameof(BlogConsts.MaxNameLength))] |
|||
public string Name { get; set; } |
|||
|
|||
[DynamicMaxLength(typeof(BlogConsts), nameof(BlogConsts.MaxSlugLength))] |
|||
[Required] |
|||
public string Slug { get; set; } |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,47 @@ |
|||
var abp = abp || {}; |
|||
$(function () { |
|||
abp.modals.createBlog = function () { |
|||
var initModal = function (publicApi, args) { |
|||
|
|||
var $name = $('#ViewModel_Name'); |
|||
var $slug = $('#ViewModel_Slug'); |
|||
|
|||
var urlEdited = false; |
|||
|
|||
$name.on('change paste keyup', function () { |
|||
reflectUrlChanges(); |
|||
}); |
|||
|
|||
$slug.on('change', function () { |
|||
reflectUrlChanges(); |
|||
}); |
|||
|
|||
function reflectUrlChanges() { |
|||
var title = $name.val(); |
|||
|
|||
if (urlEdited) { |
|||
title = $slug.val(); |
|||
} |
|||
|
|||
var slugified = slugify(title, { |
|||
lower: true |
|||
}); |
|||
|
|||
if (slugified != $slug.val()) { |
|||
reflectedChange = true; |
|||
|
|||
$slug.val(slugified); |
|||
|
|||
reflectedChange = false; |
|||
} |
|||
} |
|||
|
|||
$slug.change(function () { |
|||
urlEdited = true; |
|||
}); |
|||
} |
|||
return { |
|||
initModal: initModal |
|||
}; |
|||
}; |
|||
}); |
|||
@ -0,0 +1,85 @@ |
|||
|
|||
$(function () { |
|||
var l = abp.localization.getResource("CmsKit"); |
|||
|
|||
var createModal = new abp.ModalManager({ viewUrl: abp.appPath + "CmsKit/Blogs/CreateModal", modalClass: 'createBlog' }); |
|||
var updateModal = new abp.ModalManager({ viewUrl: abp.appPath + "CmsKit/Blogs/UpdateModal", modalClass: 'updateBlog' }); |
|||
var featuresModal = new abp.ModalManager(abp.appPath + "CmsKit/Blogs/FeaturesModal"); |
|||
|
|||
var blogsService = volo.cmsKit.admin.blogs.blogAdmin; |
|||
|
|||
var dataTable = $("#BlogsTable").DataTable(abp.libs.datatables.normalizeConfiguration({ |
|||
processing: true, |
|||
serverSide: true, |
|||
paging: true, |
|||
searching: false, |
|||
autoWidth: false, |
|||
scrollCollapse: true, |
|||
scrollX: true, |
|||
ordering: true, |
|||
order: [[1, "desc"]], |
|||
ajax: abp.libs.datatables.createAjax(blogsService.getList), |
|||
columnDefs: [ |
|||
{ |
|||
title: l("Details"), |
|||
targets: 0, |
|||
rowAction: { |
|||
items: [ |
|||
{ |
|||
text: l('Features'), |
|||
visible: abp.auth.isGranted('CmsKit.Blogs.Features'), |
|||
action: function (data) { |
|||
featuresModal.open({ blogId: data.record.id }); |
|||
} |
|||
}, |
|||
{ |
|||
text: l('Edit'), |
|||
visible: abp.auth.isGranted('CmsKit.Blogs.Update'), |
|||
action: function (data) { |
|||
updateModal.open({ id: data.record.id }); |
|||
} |
|||
}, |
|||
{ |
|||
text: l('Delete'), |
|||
visible: abp.auth.isGranted('CmsKit.Blogs.Delete'), |
|||
confirmMessage: function (data) { |
|||
return l("BlogDeletionConfirmationMessage", data.record.name) |
|||
}, |
|||
action: function (data) { |
|||
blogsService |
|||
.delete(data.record.id) |
|||
.then(function () { |
|||
abp.notify.info(l("SuccessfullyDeleted")); |
|||
dataTable.ajax.reload(); |
|||
}); |
|||
} |
|||
} |
|||
] |
|||
} |
|||
}, |
|||
{ |
|||
title: l("Name"), |
|||
orderable: true, |
|||
data: "name" |
|||
}, |
|||
{ |
|||
title: l("Slug"), |
|||
orderable: true, |
|||
data: "slug" |
|||
} |
|||
] |
|||
})); |
|||
|
|||
$('#AbpContentToolbar button[name=CreateBlog]').on('click', function (e) { |
|||
e.preventDefault(); |
|||
createModal.open(); |
|||
}); |
|||
|
|||
createModal.onResult(function () { |
|||
dataTable.ajax.reload(); |
|||
}); |
|||
|
|||
updateModal.onResult(function () { |
|||
dataTable.ajax.reload(); |
|||
}); |
|||
}); |
|||
@ -0,0 +1,30 @@ |
|||
var abp = abp || {}; |
|||
$(function () { |
|||
abp.modals.updateBlog = function () { |
|||
var initModal = function (publicApi, args) { |
|||
debugger; |
|||
var $slug = $('#ViewModel_Slug'); |
|||
|
|||
$slug.on('change', function () { |
|||
reflectUrlChanges(); |
|||
}); |
|||
|
|||
function reflectUrlChanges() { |
|||
|
|||
var title = $slug.val(); |
|||
|
|||
var slugified = slugify(title); |
|||
|
|||
if (slugified != title) { |
|||
|
|||
$slug.val(slugified, { |
|||
lower: true |
|||
}); |
|||
} |
|||
} |
|||
} |
|||
return { |
|||
initModal: initModal |
|||
}; |
|||
}; |
|||
}); |
|||
@ -0,0 +1,108 @@ |
|||
@page "{id}" |
|||
|
|||
@using System.Globalization |
|||
@using Microsoft.AspNetCore.Mvc.Localization |
|||
@using Volo.Abp.AspNetCore.Mvc.UI.Layout |
|||
@using Volo.CmsKit.Admin.Web.Pages.CmsKit.Comments |
|||
@using Volo.CmsKit.Admin.Web.Menus |
|||
@using Volo.CmsKit.Localization |
|||
|
|||
@inject IPageLayout PageLayout |
|||
@inject IHtmlLocalizer<CmsKitResource> L |
|||
|
|||
@model DetailsModel |
|||
|
|||
@{ |
|||
PageLayout.Content.Title = L["Details"].Value; |
|||
PageLayout.Content.BreadCrumb.Add(L["Menu:CMS"].Value); |
|||
PageLayout.Content.BreadCrumb.Add(L["Comments"].Value); |
|||
PageLayout.Content.MenuItemName = CmsKitAdminMenus.Comments.CommentsMenu; |
|||
} |
|||
|
|||
@section styles{ |
|||
<abp-style-bundle> |
|||
<abp-style src="/Pages/CmsKit/Comments/details.css" /> |
|||
</abp-style-bundle> |
|||
} |
|||
|
|||
@section scripts { |
|||
<abp-script-bundle> |
|||
<abp-script src="/Pages/CmsKit/Comments/details.js" /> |
|||
</abp-script-bundle> |
|||
} |
|||
|
|||
<div id="CmsKitCommentsWrapper"> |
|||
|
|||
<abp-card> |
|||
<abp-card-body> |
|||
<abp-row> |
|||
<abp-column> |
|||
<abp-table> |
|||
<tr> |
|||
<td width="10%"><b>@L["EntityType"]</b>:</td> |
|||
<td>@Model.CommentWithAuthorDto.EntityType</td> |
|||
</tr> |
|||
<tr> |
|||
<td><b>@L["EntityId"]</b>:</td> |
|||
<td>@Model.CommentWithAuthorDto.EntityId</td> |
|||
</tr> |
|||
<tr> |
|||
<td><b>@L["CreationTime"]</b>:</td> |
|||
<td>@Model.CommentWithAuthorDto.CreationTime.ToString(CultureInfo.CurrentUICulture)</td> |
|||
</tr> |
|||
<tr> |
|||
<td><b>@L["Username"]</b>:</td> |
|||
<td>@Model.CommentWithAuthorDto.Author.Name</td> |
|||
</tr> |
|||
@if (Model.CommentWithAuthorDto.RepliedCommentId.HasValue) |
|||
{ |
|||
<tr> |
|||
<td><b>@L["ReplyTo"]</b>:</td> |
|||
<td><a href="/CmsKit/Comments/Details/@Model.CommentWithAuthorDto.RepliedCommentId">@Model.CommentWithAuthorDto.RepliedCommentId</a></td> |
|||
</tr> |
|||
} |
|||
<tr> |
|||
<td class="align-text-top"><b>@L["Text"]</b>:</td> |
|||
<td>@Model.CommentWithAuthorDto.Text</td> |
|||
</tr> |
|||
</abp-table> |
|||
</abp-column> |
|||
</abp-row> |
|||
</abp-card-body> |
|||
</abp-card> |
|||
|
|||
<abp-card> |
|||
<abp-card-body> |
|||
<abp-row> |
|||
<abp-column> |
|||
<form id="CmsKitCommentsFilterForm" method="post"> |
|||
<abp-row> |
|||
<input type="hidden" name="@nameof(Model.CommentWithAuthorDto.RepliedCommentId)" value="@Model.CommentWithAuthorDto.Id"/> |
|||
|
|||
<abp-column size-lg="_6" size-md="_12" class="input-group input-daterange"> |
|||
<abp-column size="_6" style="padding-left: 0"> |
|||
<abp-input asp-for="@Model.CreationStartDate" label="@L["StartDate"].Value" type="text"/> |
|||
</abp-column> |
|||
<abp-column size="_6" style="padding-right: 0"> |
|||
<abp-input asp-for="@Model.CreationEndDate" label="@L["EndDate"].Value" type="text"/> |
|||
</abp-column> |
|||
</abp-column> |
|||
<abp-column size-lg="_4" size-md="_12"> |
|||
<abp-input asp-for="@Model.Author" label="@L["Username"].Value" type="text"/> |
|||
</abp-column> |
|||
<abp-column size-lg="_2" size-md="_12"> |
|||
<abp-button class="mt-md-4" size="Block" button-type="Primary" type="submit"> |
|||
<i class="fa fa-search" aria-hidden="true"></i> |
|||
</abp-button> |
|||
</abp-column> |
|||
</abp-row> |
|||
</form> |
|||
</abp-column> |
|||
</abp-row> |
|||
</abp-card-body> |
|||
</abp-card> |
|||
|
|||
<h3>@L["RepliesToThisComment"]</h3> |
|||
|
|||
<abp-table striped-rows="true" id="CommentsTable" class="nowrap"></abp-table> |
|||
</div> |
|||
@ -0,0 +1,33 @@ |
|||
using System; |
|||
using System.Threading.Tasks; |
|||
using Microsoft.AspNetCore.Mvc; |
|||
using Volo.CmsKit.Admin.Comments; |
|||
|
|||
namespace Volo.CmsKit.Admin.Web.Pages.CmsKit.Comments |
|||
{ |
|||
public class DetailsModel : CmsKitAdminPageModel |
|||
{ |
|||
[BindProperty(SupportsGet = true)] |
|||
public Guid Id { get; set; } |
|||
|
|||
public string Author { get; set; } |
|||
|
|||
public DateTime? CreationStartDate { get; set; } |
|||
|
|||
public DateTime? CreationEndDate { get; set; } |
|||
|
|||
public CommentWithAuthorDto CommentWithAuthorDto { get; protected set; } |
|||
|
|||
protected readonly ICommentAdminAppService CommentAdminAppService; |
|||
|
|||
public DetailsModel(ICommentAdminAppService commentAdminAppService) |
|||
{ |
|||
CommentAdminAppService = commentAdminAppService; |
|||
} |
|||
|
|||
public async Task OnGetAsync() |
|||
{ |
|||
CommentWithAuthorDto = await CommentAdminAppService.GetAsync(Id); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,71 @@ |
|||
@page |
|||
|
|||
@using Microsoft.AspNetCore.Mvc.Localization |
|||
@using Volo.Abp.AspNetCore.Mvc.UI.Layout |
|||
@using Volo.CmsKit.Admin.Web.Pages.CmsKit.Comments |
|||
@using Volo.CmsKit.Admin.Web.Menus |
|||
@using Volo.CmsKit.Localization |
|||
|
|||
@inject IPageLayout PageLayout |
|||
@inject IHtmlLocalizer<CmsKitResource> L |
|||
|
|||
@model IndexModel |
|||
|
|||
@{ |
|||
PageLayout.Content.Title = L["Comments"].Value; |
|||
PageLayout.Content.BreadCrumb.Add(L["Menu:CMS"].Value); |
|||
PageLayout.Content.MenuItemName = CmsKitAdminMenus.Comments.CommentsMenu; |
|||
|
|||
var defaultStartDate = DateTime.Now.AddDays(-7).Date.ToShortDateString(); |
|||
} |
|||
|
|||
@section styles{ |
|||
<abp-style-bundle> |
|||
<abp-style src="/Pages/CmsKit/Comments/index.css" /> |
|||
</abp-style-bundle> |
|||
} |
|||
|
|||
@section scripts { |
|||
<abp-script-bundle> |
|||
<abp-script src="/Pages/CmsKit/Comments/index.js" /> |
|||
</abp-script-bundle> |
|||
} |
|||
|
|||
<div id="CmsKitCommentsWrapper"> |
|||
<abp-card> |
|||
<abp-card-body> |
|||
<abp-row> |
|||
<abp-column> |
|||
<form id="CmsKitCommentsFilterForm" method="post"> |
|||
<abp-row> |
|||
<abp-column size-lg="_4" size-md="_12" class="input-group input-daterange"> |
|||
<abp-column size="_6" style="padding-left: 0"> |
|||
<abp-input asp-for="@Model.CreationStartDate" label="@L["StartDate"].Value" value="@defaultStartDate" type="text" /> |
|||
</abp-column> |
|||
<abp-column size="_6" style="padding-right: 0"> |
|||
<abp-input asp-for="@Model.CreationEndDate" label="@L["EndDate"].Value" type="text" /> |
|||
</abp-column> |
|||
</abp-column> |
|||
<abp-column size-lg="_2" size-md="_6"> |
|||
<abp-input asp-for="@Model.EntityType" label="@L["EntityType"].Value" type="text"/> |
|||
</abp-column> |
|||
<abp-column size-lg="_2" size-md="_6"> |
|||
<abp-input asp-for="@Model.EntityId" label="@L["EntityId"].Value" type="text"/> |
|||
</abp-column> |
|||
<abp-column size-lg="_2" size-md="_12"> |
|||
<abp-input asp-for="@Model.Author" label="@L["Username"].Value" type="text"/> |
|||
</abp-column> |
|||
<abp-column size-lg="_2" size-md="_12"> |
|||
<abp-button class="mt-md-4" size="Block" button-type="Primary" type="submit"> |
|||
<i class="fa fa-search" aria-hidden="true"></i> |
|||
</abp-button> |
|||
</abp-column> |
|||
</abp-row> |
|||
</form> |
|||
</abp-column> |
|||
</abp-row> |
|||
</abp-card-body> |
|||
</abp-card> |
|||
|
|||
<abp-table striped-rows="true" id="CommentsTable" class="nowrap"></abp-table> |
|||
</div> |
|||
@ -0,0 +1,17 @@ |
|||
using System; |
|||
|
|||
namespace Volo.CmsKit.Admin.Web.Pages.CmsKit.Comments |
|||
{ |
|||
public class IndexModel : CmsKitAdminPageModel |
|||
{ |
|||
public string EntityType { get; set; } |
|||
|
|||
public string EntityId { get; set; } |
|||
|
|||
public string Author { get; set; } |
|||
|
|||
public DateTime? CreationStartDate { get; set; } |
|||
|
|||
public DateTime? CreationEndDate { get; set; } |
|||
} |
|||
} |
|||
@ -0,0 +1,3 @@ |
|||
.datatableCell{ |
|||
cursor: pointer; |
|||
} |
|||
@ -0,0 +1,146 @@ |
|||
$(function (){ |
|||
var l = abp.localization.getResource("CmsKit"); |
|||
|
|||
var commentsService = volo.cmsKit.admin.comments.commentAdmin; |
|||
|
|||
var detailsModal = new abp.ModalManager(abp.appPath + "CmsKit/Comments/DetailsModal"); |
|||
|
|||
$(".input-daterange") |
|||
.datepicker({ |
|||
todayBtn: "linked", |
|||
autoclose: true, |
|||
language: abp.localization.currentCulture.cultureName, |
|||
}) |
|||
.on("hide", function (e) { |
|||
e.stopPropagation(); |
|||
}); |
|||
|
|||
var filterForm = $('#CmsKitCommentsFilterForm'); |
|||
|
|||
var getFilter = function () { |
|||
var filterObj = filterForm.serializeFormToObject(); |
|||
|
|||
var startDate = luxon.DateTime.fromFormat( |
|||
filterObj.creationStartDate, |
|||
abp.localization.currentCulture.dateTimeFormat.shortDatePattern, |
|||
{ locale: abp.localization.currentCulture.cultureName } |
|||
); |
|||
if (!startDate.invalid) { |
|||
filterObj.creationStartDate = startDate.toFormat("yyyy-MM-dd"); |
|||
} |
|||
|
|||
var endDate = luxon.DateTime.fromFormat( |
|||
filterObj.creationEndDate, |
|||
abp.localization.currentCulture.dateTimeFormat.shortDatePattern, |
|||
{ locale: abp.localization.currentCulture.cultureName } |
|||
); |
|||
if (!endDate.invalid) { |
|||
filterObj.creationEndDate = endDate.toFormat("yyyy-MM-dd"); |
|||
} |
|||
|
|||
return filterObj; |
|||
}; |
|||
|
|||
var _dataTable = $('#CommentsTable').DataTable(abp.libs.datatables.normalizeConfiguration({ |
|||
processing: true, |
|||
serverSide: true, |
|||
paging: true, |
|||
scrollX: true, |
|||
searching: false, |
|||
scrollCollapse: true, |
|||
ajax: abp.libs.datatables.createAjax(commentsService.getList, getFilter), |
|||
columnDefs: [ |
|||
{ |
|||
width: "10%", |
|||
title: l("Actions"), |
|||
targets: 0, |
|||
orderable: false, |
|||
rowAction: { |
|||
items: [ |
|||
{ |
|||
text: l('Details'), |
|||
action: function (data) { |
|||
window.location = abp.appPath + 'CmsKit/Comments/Details/' + data.record.id; |
|||
} |
|||
}, |
|||
{ |
|||
text: l('Delete'), |
|||
visible: abp.auth.isGranted('CmsKit.Comments.Delete'), |
|||
confirmMessage: function (data) { |
|||
return l("CommentDeletionConfirmationMessage") |
|||
}, |
|||
action: function (data) { |
|||
commentsService |
|||
.delete(data.record.id) |
|||
.then(function () { |
|||
abp.notify.info(l("SuccessfullyDeleted")); |
|||
_dataTable.ajax.reload(); |
|||
}); |
|||
} |
|||
} |
|||
] |
|||
} |
|||
}, |
|||
{ |
|||
width: "10%", |
|||
title: l("Username"), |
|||
orderable: false, |
|||
data: "author.userName", |
|||
render: function (data) { |
|||
if (data !== null) { |
|||
return GetFilterableDatatableContent('#Author', data); |
|||
} |
|||
return ""; |
|||
} |
|||
}, |
|||
{ |
|||
title: l("Text"), |
|||
data: "text", |
|||
orderable: false, |
|||
render: function (data) { |
|||
data = data || ""; |
|||
|
|||
var maxChars = 64; |
|||
|
|||
if (data.length > maxChars) { |
|||
return ( |
|||
'<span data-toggle="tooltip" title="' + |
|||
data + |
|||
'">' + |
|||
data.substring(0, maxChars) + |
|||
"..." + |
|||
"</span>" |
|||
); |
|||
} else { |
|||
return data; |
|||
} |
|||
} |
|||
}, |
|||
{ |
|||
width: "15%", |
|||
title: l("CreationTime"), |
|||
data: "creationTime", |
|||
orderable: true, |
|||
dataFormat: "datetime" |
|||
} |
|||
] |
|||
})); |
|||
|
|||
function GetFilterableDatatableContent(filterSelector, data){ |
|||
return '<span class="datatableCell" data-field="'+ filterSelector +'" data-val="'+ data +'">' + data + '</span>'; |
|||
} |
|||
|
|||
$(document).on('click', '.datatableCell', function () { |
|||
var inputSelector = $(this).attr('data-field'); |
|||
var value = $(this).attr('data-val'); |
|||
|
|||
$(inputSelector).val(value); |
|||
|
|||
_dataTable.ajax.reload(); |
|||
}); |
|||
|
|||
filterForm.submit(function (e){ |
|||
e.preventDefault(); |
|||
_dataTable.ajax.reload(); |
|||
}); |
|||
}); |
|||
@ -0,0 +1,3 @@ |
|||
.datatableCell{ |
|||
cursor: pointer; |
|||
} |
|||
@ -0,0 +1,158 @@ |
|||
$(function (){ |
|||
var l = abp.localization.getResource("CmsKit"); |
|||
|
|||
var commentsService = volo.cmsKit.admin.comments.commentAdmin; |
|||
|
|||
var detailsModal = new abp.ModalManager(abp.appPath + "CmsKit/Comments/DetailsModal"); |
|||
|
|||
$(".input-daterange") |
|||
.datepicker({ |
|||
todayBtn: "linked", |
|||
autoclose: true, |
|||
language: abp.localization.currentCulture.cultureName, |
|||
}) |
|||
.on("hide", function (e) { |
|||
e.stopPropagation(); |
|||
}); |
|||
|
|||
var filterForm = $('#CmsKitCommentsFilterForm'); |
|||
|
|||
var getFilter = function () { |
|||
var filterObj = filterForm.serializeFormToObject(); |
|||
|
|||
var startDate = luxon.DateTime.fromFormat( |
|||
filterObj.creationStartDate, |
|||
abp.localization.currentCulture.dateTimeFormat.shortDatePattern, |
|||
{ locale: abp.localization.currentCulture.cultureName } |
|||
); |
|||
if (!startDate.invalid) { |
|||
filterObj.creationStartDate = startDate.toFormat("yyyy-MM-dd"); |
|||
} |
|||
|
|||
var endDate = luxon.DateTime.fromFormat( |
|||
filterObj.creationEndDate, |
|||
abp.localization.currentCulture.dateTimeFormat.shortDatePattern, |
|||
{ locale: abp.localization.currentCulture.cultureName } |
|||
); |
|||
if (!endDate.invalid) { |
|||
filterObj.creationEndDate = endDate.toFormat("yyyy-MM-dd"); |
|||
} |
|||
|
|||
return filterObj; |
|||
}; |
|||
|
|||
var _dataTable = $('#CommentsTable').DataTable(abp.libs.datatables.normalizeConfiguration({ |
|||
processing: true, |
|||
serverSide: true, |
|||
paging: true, |
|||
scrollX: true, |
|||
searching: false, |
|||
scrollCollapse: true, |
|||
ajax: abp.libs.datatables.createAjax(commentsService.getList, getFilter), |
|||
columnDefs: [ |
|||
{ |
|||
width: "10%", |
|||
title: l("Actions"), |
|||
targets: 0, |
|||
orderable: false, |
|||
rowAction: { |
|||
items: [ |
|||
{ |
|||
text: l('Details'), |
|||
action: function (data) { |
|||
window.location = abp.appPath + 'CmsKit/Comments/Details/' + data.record.id; |
|||
} |
|||
}, |
|||
{ |
|||
text: l('Delete'), |
|||
visible: abp.auth.isGranted('CmsKit.Comments.Delete'), |
|||
confirmMessage: function (data) { |
|||
return l("CommentDeletionConfirmationMessage") |
|||
}, |
|||
action: function (data) { |
|||
commentsService |
|||
.delete(data.record.id) |
|||
.then(function () { |
|||
abp.notify.info(l("SuccessfullyDeleted")); |
|||
_dataTable.ajax.reload(); |
|||
}); |
|||
} |
|||
} |
|||
] |
|||
} |
|||
}, |
|||
{ |
|||
width: "10%", |
|||
title: l("Username"), |
|||
orderable: false, |
|||
data: "author.userName", |
|||
render: function (data) { |
|||
if (data !== null) { |
|||
return GetFilterableDatatableContent('#Author', data); |
|||
} |
|||
return ""; |
|||
} |
|||
}, |
|||
{ |
|||
width: "15%", |
|||
title: l("EntityType"), |
|||
orderable: false, |
|||
data: "entityType", |
|||
render: function (data) { |
|||
if (data !== null) { |
|||
return GetFilterableDatatableContent('#EntityType', data); |
|||
} |
|||
return ""; |
|||
} |
|||
}, |
|||
{ |
|||
title: l("Text"), |
|||
data: "text", |
|||
orderable: false, |
|||
render: function (data) { |
|||
data = data || ""; |
|||
|
|||
var maxChars = 64; |
|||
|
|||
if (data.length > maxChars) { |
|||
return ( |
|||
'<span data-toggle="tooltip" title="' + |
|||
data + |
|||
'">' + |
|||
data.substring(0, maxChars) + |
|||
"..." + |
|||
"</span>" |
|||
); |
|||
} else { |
|||
return data; |
|||
} |
|||
} |
|||
}, |
|||
{ |
|||
width: "15%", |
|||
title: l("CreationTime"), |
|||
data: "creationTime", |
|||
orderable: true, |
|||
dataFormat: "datetime" |
|||
} |
|||
] |
|||
})); |
|||
|
|||
function GetFilterableDatatableContent(filterSelector, data){ |
|||
return '<span class="datatableCell" data-field="'+ filterSelector +'" data-val="'+ data +'">' + data + '</span>'; |
|||
} |
|||
|
|||
$(document).on('click', '.datatableCell', function () { |
|||
var inputSelector = $(this).attr('data-field'); |
|||
var value = $(this).attr('data-val'); |
|||
|
|||
$(inputSelector).val(value); |
|||
|
|||
_dataTable.ajax.reload(); |
|||
}); |
|||
|
|||
filterForm.submit(function (e){ |
|||
e.preventDefault(); |
|||
_dataTable.ajax.reload(); |
|||
}); |
|||
}); |
|||
@ -0,0 +1,44 @@ |
|||
using Microsoft.AspNetCore.Mvc; |
|||
using Microsoft.AspNetCore.Mvc.ViewFeatures; |
|||
using System.Threading.Tasks; |
|||
using Volo.Abp.AspNetCore.Mvc; |
|||
using Volo.Abp.AspNetCore.Mvc.UI.Packages.TuiEditor; |
|||
using Volo.Abp.AspNetCore.Mvc.UI.Packages.Uppy; |
|||
using Volo.Abp.AspNetCore.Mvc.UI.Widgets; |
|||
|
|||
namespace Volo.CmsKit.Admin.Web.Pages.CmsKit.Contents.Components.ContentEditor |
|||
{ |
|||
[Widget( |
|||
StyleTypes = new[] |
|||
{ |
|||
typeof(TuiEditorStyleContributor) |
|||
}, |
|||
ScriptTypes = new[] |
|||
{ |
|||
typeof(TuiEditorScriptContributor), |
|||
typeof(UppyScriptContributor) |
|||
}, |
|||
ScriptFiles = new[] |
|||
{ |
|||
"/Pages/CmsKit/Contents/Components/ContentEditor/default.js" |
|||
})] |
|||
public class ContentEditorViewComponent : AbpViewComponent |
|||
{ |
|||
public async Task<IViewComponentResult> InvokeAsync(string inputId) |
|||
{ |
|||
return View( |
|||
"~/Pages/CmsKit/Contents/Components/ContentEditor/Default.cshtml", |
|||
new ContentEditorViewModel(inputId)); |
|||
} |
|||
|
|||
public class ContentEditorViewModel |
|||
{ |
|||
public ContentEditorViewModel(string inputId) |
|||
{ |
|||
InputId = inputId; |
|||
} |
|||
|
|||
public string InputId { get; set; } |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,7 @@ |
|||
@using System.Globalization |
|||
@using Volo.CmsKit.Admin.Web.Pages.CmsKit.Contents.Components.ContentEditor |
|||
|
|||
@model ContentEditorViewComponent.ContentEditorViewModel |
|||
|
|||
<div class="content-editor" id="@Model.InputId-container" data-input-id="@Model.InputId" data-language="@(CultureInfo.CurrentUICulture.TwoLetterISOLanguageName)"> |
|||
</div> |
|||
@ -0,0 +1,80 @@ |
|||
$(function () { |
|||
var fileUploadUri = "/api/cms-kit-admin/media"; |
|||
var fileUriPrefix = "/api/cms-kit/media/"; |
|||
|
|||
var editorDataKey = "tuiEditor"; |
|||
|
|||
initAllEditors(); |
|||
|
|||
function initAllEditors() { |
|||
$('.content-editor').each(function (i, item) { |
|||
initEditor(item); |
|||
}); |
|||
} |
|||
|
|||
function initEditor(element) { |
|||
var $editorContainer = $(element); |
|||
var inputName = $editorContainer.data('input-id'); |
|||
var $editorInput = $('#' + inputName); |
|||
var initialValue = $editorInput.val(); |
|||
|
|||
var editor = $editorContainer.tuiEditor({ |
|||
usageStatistics: false, |
|||
useCommandShortcut: true, |
|||
initialValue: initialValue, |
|||
previewStyle: 'tab', |
|||
height: "25em", |
|||
minHeight: "25em", |
|||
initialEditType: initialValue ? 'wysiwyg' : 'markdown', |
|||
language: $editorContainer.data("language"), |
|||
hooks: { |
|||
addImageBlobHook: uploadFile, |
|||
}, |
|||
events: { |
|||
change: function (_val) { |
|||
$editorInput.val(editor.getHtml()); |
|||
$editorInput.trigger("change"); |
|||
} |
|||
} |
|||
}).data(editorDataKey); |
|||
} |
|||
|
|||
function getUppyHeaders() { |
|||
var headers = {}; |
|||
headers[abp.security.antiForgery.tokenHeaderName] = abp.security.antiForgery.getToken(); |
|||
|
|||
return headers; |
|||
} |
|||
|
|||
function uploadFile(blob, callback, source) { |
|||
var UPPY_OPTIONS = { |
|||
endpoint: fileUploadUri, |
|||
formData: true, |
|||
fieldName: "file", |
|||
method: "post", |
|||
headers: getUppyHeaders() |
|||
}; |
|||
|
|||
var UPPY = Uppy.Core().use(Uppy.XHRUpload, UPPY_OPTIONS); |
|||
|
|||
UPPY.reset(); |
|||
|
|||
UPPY.addFile({ |
|||
id: "content-file", |
|||
name: blob.name, |
|||
type: blob.type, |
|||
data: blob, |
|||
}); |
|||
|
|||
UPPY.upload().then((result) => { |
|||
if (result.failed.length > 0) { |
|||
abp.message.error("File upload failed"); |
|||
} else { |
|||
var mediaDto = result.successful[0].response.body; |
|||
var fileUrl = (fileUriPrefix + mediaDto.id); |
|||
|
|||
callback(fileUrl, mediaDto.name); |
|||
} |
|||
}); |
|||
} |
|||
}); |
|||
@ -0,0 +1,28 @@ |
|||
using Microsoft.AspNetCore.Mvc; |
|||
using System; |
|||
|
|||
namespace Volo.CmsKit.Admin.Web.Pages.CmsKit.Contents.Components.EntityContentEditor |
|||
{ |
|||
public class ContentViewModel |
|||
{ |
|||
public ContentViewModel(string entityType, string entityId, string value = null, Guid? id = null) |
|||
{ |
|||
EntityType = entityType; |
|||
EntityId = entityId; |
|||
Value = value; |
|||
Id = id; |
|||
} |
|||
|
|||
[HiddenInput] |
|||
public string EntityType { get; set; } |
|||
|
|||
[HiddenInput] |
|||
public string EntityId { get; set; } |
|||
|
|||
[HiddenInput] |
|||
public string Value { get; set; } |
|||
|
|||
[HiddenInput] |
|||
public Guid? Id { get; set; } |
|||
} |
|||
} |
|||
@ -0,0 +1,27 @@ |
|||
@using Volo.CmsKit.Admin.Web.Pages.CmsKit.Contents.Components.EntityContentEditor |
|||
@using Volo.CmsKit.Admin.Web.Pages.CmsKit.Contents.Components.ContentEditor |
|||
@using Volo.CmsKit.Localization |
|||
@using Microsoft.Extensions.Localization |
|||
|
|||
@model EntityContentEditorViewComponent.EntityContentEditorViewModel |
|||
|
|||
@inject IStringLocalizer<CmsKitResource> L |
|||
|
|||
@if (Model.DisplaySubmitButton) |
|||
{ |
|||
<abp-dynamic-form abp-model="ViewModel" class="form-entity-content-editor"> |
|||
|
|||
<abp-form-content /> |
|||
|
|||
<abp-button button-type="Primary" type="submit" text="@L["Submit"]" /> |
|||
</abp-dynamic-form> |
|||
} |
|||
else |
|||
{ |
|||
<abp-input asp-for="ViewModel.Id" /> |
|||
<abp-input asp-for="ViewModel.EntityId" /> |
|||
<abp-input asp-for="ViewModel.EntityType" /> |
|||
<abp-input asp-for="ViewModel.Value" /> |
|||
} |
|||
|
|||
@await Component.InvokeAsync(typeof(ContentEditorViewComponent), new { inputId = Html.IdFor(m => m.ViewModel.Value) }) |
|||
@ -0,0 +1,65 @@ |
|||
using Microsoft.AspNetCore.Mvc; |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
using System.Text; |
|||
using System.Threading.Tasks; |
|||
using Volo.Abp.AspNetCore.Mvc; |
|||
using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form; |
|||
using Volo.Abp.AspNetCore.Mvc.UI.Widgets; |
|||
using Volo.Abp.Domain.Entities; |
|||
using Volo.CmsKit.Admin.Contents; |
|||
|
|||
namespace Volo.CmsKit.Admin.Web.Pages.CmsKit.Contents.Components.EntityContentEditor |
|||
{ |
|||
[Widget( |
|||
ScriptFiles = new[] |
|||
{ |
|||
"/Pages/CmsKit/Contents/Components/EntityContentEditor/default.js" |
|||
})] |
|||
public class EntityContentEditorViewComponent : AbpViewComponent |
|||
{ |
|||
private readonly IContentAdminAppService contentAdminAppService; |
|||
|
|||
public EntityContentEditorViewComponent(IContentAdminAppService contentAdminAppService) |
|||
{ |
|||
this.contentAdminAppService = contentAdminAppService; |
|||
} |
|||
|
|||
public async Task<IViewComponentResult> InvokeAsync(string entityType, string entityId, bool displaySubmitButton = true) |
|||
{ |
|||
var viewModel = new ContentViewModel(entityType, entityId); |
|||
|
|||
try |
|||
{ |
|||
if (entityId != null) |
|||
{ |
|||
var content = await contentAdminAppService.GetAsync(entityType, entityId); |
|||
viewModel.Value = content.Value; |
|||
viewModel.Id = content.Id; |
|||
} |
|||
} |
|||
catch (EntityNotFoundException) |
|||
{ |
|||
// Initialize editor even content doesn't exist.
|
|||
} |
|||
|
|||
return View( |
|||
"~/Pages/CmsKit/Contents/Components/EntityContentEditor/Default.cshtml", |
|||
new EntityContentEditorViewModel(viewModel, displaySubmitButton)); |
|||
} |
|||
|
|||
public class EntityContentEditorViewModel |
|||
{ |
|||
public ContentViewModel ViewModel { get; set; } |
|||
|
|||
public bool DisplaySubmitButton { get; set; } |
|||
|
|||
public EntityContentEditorViewModel(ContentViewModel viewModel, bool displaySubmitButton) |
|||
{ |
|||
ViewModel = viewModel; |
|||
DisplaySubmitButton = displaySubmitButton; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,34 @@ |
|||
$(function () { |
|||
|
|||
$entityContentEditors = $('.form-entity-content-editor'); |
|||
|
|||
var contentAdminService = volo.cmsKit.admin.contents.contentAdmin; |
|||
|
|||
$entityContentEditors.on('submit', function (e, obj) { |
|||
e.preventDefault(); |
|||
|
|||
var $form = $(e.currentTarget); |
|||
|
|||
if ($form.valid()) { |
|||
|
|||
var data = form.serializeFormToObject().viewModel; |
|||
|
|||
abp.ui.setBusy(e); |
|||
if (data.id) { |
|||
contentAdminService |
|||
.update(data.id, data) |
|||
.then(function (result) { |
|||
abp.ui.clearBusy(); |
|||
}); |
|||
|
|||
} |
|||
else { |
|||
contentAdminService |
|||
.create(data) |
|||
.then(function (result) { |
|||
abp.ui.clearBusy(); |
|||
}); |
|||
} |
|||
} |
|||
}) |
|||
}) |
|||
@ -0,0 +1,45 @@ |
|||
@page |
|||
|
|||
@using Volo.CmsKit.Admin.Web.Pages.CmsKit.Contents.Components.EntityContentEditor |
|||
@using Volo.CmsKit.Admin.Web.Pages |
|||
@using Volo.CmsKit.Admin.Web.Menus |
|||
@using Volo.CmsKit.Admin.Web.Pages.CmsKit.Pages |
|||
@using Volo.CmsKit.Admin.Web.Bundles |
|||
|
|||
@inherits CmsKitAdminPageBase |
|||
|
|||
@model CreateModel |
|||
|
|||
@{ |
|||
PageLayout.Content.Title = L["Pages"].Value; |
|||
PageLayout.Content.BreadCrumb.Add(L["Menu:CMS"].Value); |
|||
PageLayout.Content.MenuItemName = CmsKitAdminMenus.Pages.PagesMenu; |
|||
} |
|||
|
|||
@section scripts { |
|||
<abp-script-bundle> |
|||
<abp-script src="/Pages/CmsKit/Pages/create.js" /> |
|||
<abp-script type="typeof(SlugifyScriptContributor)" /> |
|||
</abp-script-bundle> |
|||
} |
|||
|
|||
<abp-card> |
|||
<abp-card-header title="@L["New"].Value"></abp-card-header> |
|||
<abp-card-body> |
|||
<abp-dynamic-form abp-model="ViewModel" asp-page="/CmsKit/Pages/Create" id="form-page-create"> |
|||
<abp-form-content /> |
|||
|
|||
<abp-input asp-for="ViewModel.Slug" title="@L["PageSlugInformation"]" data-toggle="tooltip"/> |
|||
</abp-dynamic-form> |
|||
|
|||
@await Component.InvokeAsync(typeof(EntityContentEditorViewComponent), new |
|||
{ |
|||
entityType = "Page", |
|||
displaySubmitButton = false |
|||
}) |
|||
|
|||
</abp-card-body> |
|||
<abp-card-footer> |
|||
<abp-button button-type="Primary" type="submit" text="@L["Submit"].Value" id="button-page-create" /> |
|||
</abp-card-footer> |
|||
</abp-card> |
|||
@ -0,0 +1,47 @@ |
|||
using AutoMapper; |
|||
using Microsoft.AspNetCore.Mvc; |
|||
using System.ComponentModel.DataAnnotations; |
|||
using System.Threading.Tasks; |
|||
using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form; |
|||
using Volo.Abp.Validation; |
|||
using Volo.CmsKit.Admin.Pages; |
|||
using Volo.CmsKit.Admin.Web.Pages; |
|||
using Volo.CmsKit.Pages; |
|||
|
|||
namespace Volo.CmsKit.Admin.Web.Pages.CmsKit.Pages |
|||
{ |
|||
public class CreateModel : CmsKitAdminPageModel |
|||
{ |
|||
protected readonly IPageAdminAppService pageAdminAppService; |
|||
|
|||
[BindProperty] |
|||
public CreatePageViewModel ViewModel { get; set; } |
|||
|
|||
public CreateModel(IPageAdminAppService pageAdminAppService) |
|||
{ |
|||
this.pageAdminAppService = pageAdminAppService; |
|||
} |
|||
|
|||
public async Task<IActionResult> OnPostAsync() |
|||
{ |
|||
var createInput = ObjectMapper.Map<CreatePageViewModel, CreatePageInputDto>(ViewModel); |
|||
|
|||
var created = await pageAdminAppService.CreateAsync(createInput); |
|||
|
|||
return new OkObjectResult(created); |
|||
} |
|||
|
|||
[AutoMap(typeof(CreatePageInputDto), ReverseMap = true)] |
|||
public class CreatePageViewModel |
|||
{ |
|||
[DynamicMaxLength(typeof(PageConsts), nameof(PageConsts.MaxTitleLength))] |
|||
[Required] |
|||
public string Title { get; set; } |
|||
|
|||
[DynamicMaxLength(typeof(PageConsts), nameof(PageConsts.MaxSlugLength))] |
|||
[Required] |
|||
[DynamicFormIgnore] |
|||
public string Slug { get; set; } |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,40 @@ |
|||
@page |
|||
|
|||
@using Volo.Abp.AspNetCore.Mvc.UI.Layout |
|||
@using Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Pages.Shared.Components.AbpPageToolbar |
|||
@using Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Pages.Shared.Components.AbpPageSearchBox |
|||
@using Volo.CmsKit.Admin.Web.Pages |
|||
@using Volo.CmsKit.Admin.Web.Menus |
|||
@using Volo.CmsKit.Admin.Web.Pages.CmsKit.Pages |
|||
|
|||
@inherits CmsKitAdminPageBase |
|||
|
|||
@model IndexModel |
|||
|
|||
@{ |
|||
PageLayout.Content.Title = L["Pages"].Value; |
|||
PageLayout.Content.BreadCrumb.Add(L["Menu:CMS"].Value); |
|||
PageLayout.Content.MenuItemName = CmsKitAdminMenus.Pages.PagesMenu; |
|||
} |
|||
|
|||
@section scripts { |
|||
<abp-script src="/Pages/CmsKit/Pages/index.js"/> |
|||
} |
|||
|
|||
@section content_toolbar { |
|||
@await Component.InvokeAsync(typeof(AbpPageToolbarViewComponent), new {pageName = typeof(IndexModel).FullName}) |
|||
} |
|||
|
|||
<div id="CmsKitPagesWrapper"> |
|||
<abp-card> |
|||
<abp-card-body> |
|||
<abp-row> |
|||
<abp-column> |
|||
@await Component.InvokeAsync(typeof(AbpPageSearchBoxViewComponent)) |
|||
</abp-column> |
|||
</abp-row> |
|||
</abp-card-body> |
|||
</abp-card> |
|||
|
|||
<abp-table striped-rows="true" id="PagesTable" class="nowrap"></abp-table> |
|||
</div> |
|||
@ -0,0 +1,11 @@ |
|||
|
|||
namespace Volo.CmsKit.Admin.Web.Pages.CmsKit.Pages |
|||
{ |
|||
public class IndexModel : CmsKitAdminPageModel |
|||
{ |
|||
public void OnGet() |
|||
{ |
|||
|
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,45 @@ |
|||
@page "{Id}" |
|||
|
|||
@using Volo.CmsKit.Admin.Web.Pages.CmsKit.Contents.Components.EntityContentEditor |
|||
@using Volo.CmsKit.Admin.Web.Menus |
|||
@using Volo.CmsKit.Admin.Web.Pages.CmsKit.Pages |
|||
@using Volo.CmsKit.Admin.Web.Pages |
|||
|
|||
@inherits CmsKitAdminPageBase |
|||
|
|||
@model UpdateModel |
|||
|
|||
@{ |
|||
PageLayout.Content.Title = L["Pages"].Value; |
|||
PageLayout.Content.BreadCrumb.Add(L["Menu:CMS"].Value); |
|||
PageLayout.Content.MenuItemName = CmsKitAdminMenus.Pages.PagesMenu; |
|||
} |
|||
|
|||
|
|||
@section scripts { |
|||
<abp-script src="/Pages/CmsKit/Pages/update.js" /> |
|||
} |
|||
|
|||
<abp-card> |
|||
<abp-card-header title="@L["Update"].Value"></abp-card-header> |
|||
<abp-card-body> |
|||
<abp-dynamic-form abp-model="ViewModel" asp-page="/CmsKit/Pages/Update" id="form-page-update"> |
|||
<abp-input asp-for="Id" /> |
|||
|
|||
<abp-form-content /> |
|||
|
|||
<abp-input asp-for="ViewModel.Slug" title="@L["PageSlugInformation"]" data-toggle="tooltip" /> |
|||
</abp-dynamic-form> |
|||
|
|||
@await Component.InvokeAsync(typeof(EntityContentEditorViewComponent), new |
|||
{ |
|||
entityType = "Page", |
|||
entityId = Model.Id.ToString(), |
|||
displaySubmitButton = false |
|||
}) |
|||
|
|||
</abp-card-body> |
|||
<abp-card-footer> |
|||
<abp-button button-type="Primary" type="submit" text="@L["Submit"].Value" id="button-page-update" /> |
|||
</abp-card-footer> |
|||
</abp-card> |
|||
@ -0,0 +1,62 @@ |
|||
using AutoMapper; |
|||
using Microsoft.AspNetCore.Mvc; |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.ComponentModel.DataAnnotations; |
|||
using System.Linq; |
|||
using System.Text; |
|||
using System.Threading.Tasks; |
|||
using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form; |
|||
using Volo.Abp.Validation; |
|||
using Volo.CmsKit.Admin.Pages; |
|||
using Volo.CmsKit.Pages; |
|||
|
|||
namespace Volo.CmsKit.Admin.Web.Pages.CmsKit.Pages |
|||
{ |
|||
public class UpdateModel : CmsKitAdminPageModel |
|||
{ |
|||
[BindProperty(SupportsGet = true)] |
|||
[HiddenInput] |
|||
public Guid Id { get; set; } |
|||
|
|||
[BindProperty] |
|||
public UpdatePageViewModel ViewModel { get; set; } |
|||
|
|||
protected readonly IPageAdminAppService pageAdminAppService; |
|||
|
|||
public UpdateModel(IPageAdminAppService pageAdminAppService) |
|||
{ |
|||
this.pageAdminAppService = pageAdminAppService; |
|||
} |
|||
|
|||
public async Task OnGetAsync() |
|||
{ |
|||
var dto = await pageAdminAppService.GetAsync(Id); |
|||
|
|||
ViewModel = ObjectMapper.Map<PageDto, UpdatePageViewModel>(dto); |
|||
} |
|||
|
|||
public async Task<IActionResult> OnPostAsync() |
|||
{ |
|||
var updateInput = ObjectMapper.Map<UpdatePageViewModel, UpdatePageInputDto>(ViewModel); |
|||
|
|||
await pageAdminAppService.UpdateAsync(Id, updateInput); |
|||
|
|||
return NoContent(); |
|||
} |
|||
|
|||
[AutoMap(typeof(PageDto))] |
|||
[AutoMap(typeof(UpdatePageInputDto), ReverseMap = true)] |
|||
public class UpdatePageViewModel |
|||
{ |
|||
[DynamicMaxLength(typeof(PageConsts), nameof(PageConsts.MaxTitleLength))] |
|||
[Required] |
|||
public string Title { get; set; } |
|||
|
|||
[DynamicMaxLength(typeof(PageConsts), nameof(PageConsts.MaxSlugLength))] |
|||
[Required] |
|||
[DynamicFormIgnore] |
|||
public string Slug { get; set; } |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,72 @@ |
|||
$(function () { |
|||
var l = abp.localization.getResource("CmsKit"); |
|||
|
|||
var $formCreate = $('#form-page-create'); |
|||
var $title = $('#ViewModel_Title'); |
|||
var $slug = $('#ViewModel_Slug'); |
|||
var $buttonSubmit = $('#button-page-create'); |
|||
var $pageContentInput = $('#ViewModel_Value'); |
|||
|
|||
$formCreate.on('submit', function (e) { |
|||
e.preventDefault(); |
|||
|
|||
if ($formCreate.valid()) { |
|||
|
|||
abp.ui.setBusy(); |
|||
|
|||
$formCreate.ajaxSubmit({ |
|||
success: function (result) { |
|||
submitEntityContent(result.id); |
|||
} |
|||
}); |
|||
} |
|||
}); |
|||
|
|||
$buttonSubmit.click(function (e) { |
|||
e.preventDefault(); |
|||
$formCreate.submit(); |
|||
}); |
|||
|
|||
function submitEntityContent(pageId) { |
|||
volo.cmsKit.admin.contents.contentAdmin |
|||
.create( |
|||
{ |
|||
entityType: 'Page', |
|||
entityId: pageId, |
|||
value: $pageContentInput.val() |
|||
}) |
|||
.then(function (result) { |
|||
finishSaving(); |
|||
}); |
|||
} |
|||
|
|||
function finishSaving() { |
|||
abp.notify.success(l('SuccessfullySaved')); |
|||
abp.ui.clearBusy(); |
|||
location.href = "/CmsKit/Pages/"; |
|||
} |
|||
|
|||
var slugEdited = false; |
|||
|
|||
$title.on('change paste keyup', function () { |
|||
var title = $title.val(); |
|||
|
|||
if (slugEdited) { |
|||
title = $slug.val(); |
|||
} |
|||
|
|||
var slugified = slugify(title, { |
|||
lower: true |
|||
}); |
|||
|
|||
if (slugified != $slug.val()) { |
|||
reflectedChange = true; |
|||
$slug.val(slugified); |
|||
reflectedChange = false; |
|||
} |
|||
}); |
|||
|
|||
$slug.change(function () { |
|||
slugEdited = true; |
|||
}); |
|||
}); |
|||
@ -0,0 +1,81 @@ |
|||
$(function (){ |
|||
var l = abp.localization.getResource("CmsKit"); |
|||
|
|||
var pagesService = volo.cmsKit.admin.pages.pageAdmin; |
|||
|
|||
var getFilter = function () { |
|||
return { |
|||
filter: $('#CmsKitPagesWrapper input.page-search-filter-text').val() |
|||
}; |
|||
}; |
|||
|
|||
var _dataTable = $("#PagesTable").DataTable(abp.libs.datatables.normalizeConfiguration({ |
|||
processing: true, |
|||
serverSide: true, |
|||
paging: true, |
|||
searching: false, |
|||
autoWidth: false, |
|||
scrollCollapse: true, |
|||
scrollX: true, |
|||
ordering: true, |
|||
order: [[3, "desc"]], |
|||
ajax: abp.libs.datatables.createAjax(pagesService.getList, getFilter), |
|||
columnDefs: [ |
|||
{ |
|||
title: l("Details"), |
|||
targets: 0, |
|||
rowAction: { |
|||
items: [ |
|||
{ |
|||
text: l('Edit'), |
|||
visible: abp.auth.isGranted('CmsKit.Pages.Update'), |
|||
action: function (data) { |
|||
location.href = '/CmsKit/Pages/Update/' + data.record.id; |
|||
} |
|||
}, |
|||
{ |
|||
text: l('Delete'), |
|||
visible: abp.auth.isGranted('CmsKit.Pages.Delete'), |
|||
confirmMessage: function (data) { |
|||
return l("PageDeletionConfirmationMessage") |
|||
}, |
|||
action: function (data) { |
|||
pagesService |
|||
.delete(data.record.id) |
|||
.then(function () { |
|||
abp.notify.info(l("SuccessfullyDeleted")); |
|||
_dataTable.ajax.reload(); |
|||
}); |
|||
} |
|||
} |
|||
] |
|||
} |
|||
}, |
|||
{ |
|||
title: l("Title"), |
|||
orderable: true, |
|||
data: "title" |
|||
}, |
|||
{ |
|||
title: l("Slug"), |
|||
orderable: true, |
|||
data: "slug" |
|||
}, |
|||
{ |
|||
title: l("CreationTime"), |
|||
orderable: true, |
|||
data: 'creationTime' |
|||
} |
|||
] |
|||
})); |
|||
|
|||
$('#CmsKitPagesWrapper form.page-search-form').submit(function (e) { |
|||
e.preventDefault(); |
|||
_dataTable.ajax.reload(); |
|||
}); |
|||
|
|||
$('#AbpContentToolbar button[name=CreatePage]').on('click', function (e) { |
|||
e.preventDefault(); |
|||
window.location.href = "/CmsKit/Pages/Create" |
|||
}); |
|||
}); |
|||
@ -0,0 +1,65 @@ |
|||
$(function () { |
|||
|
|||
var l = abp.localization.getResource("CmsKit"); |
|||
|
|||
var $formUpdate = $('#form-page-update'); |
|||
var $buttonSubmit = $('#button-page-update'); |
|||
var $pageContentInput = $('#ViewModel_Value'); |
|||
var $pageIdInput = $('#Id'); |
|||
var $contentIdInput = $('#ViewModel_Id'); |
|||
|
|||
$formUpdate.on('submit', function (e) { |
|||
e.preventDefault(); |
|||
|
|||
if ($formUpdate.valid()) { |
|||
|
|||
abp.ui.setBusy(); |
|||
|
|||
$formUpdate.ajaxSubmit({ |
|||
success: function (result) { |
|||
submitEntityContent(); |
|||
} |
|||
}); |
|||
} |
|||
}); |
|||
|
|||
$buttonSubmit.click(function (e) { |
|||
e.preventDefault(); |
|||
$formUpdate.submit(); |
|||
}); |
|||
|
|||
function submitEntityContent() { |
|||
|
|||
var contentId = $contentIdInput.val(); |
|||
var pageId = $pageIdInput.val(); |
|||
var contentValue = $pageContentInput.val(); |
|||
|
|||
if (contentId) { |
|||
volo.cmsKit.admin.contents.contentAdmin |
|||
.update(contentId, |
|||
{ |
|||
value: contentValue |
|||
}) |
|||
.then(function (result) { |
|||
finishSaving(result); |
|||
}); |
|||
} |
|||
else { |
|||
volo.cmsKit.admin.contents.contentAdmin |
|||
.create({ |
|||
entityType: 'Page', |
|||
entityId: pageId, |
|||
value: contentValue |
|||
}) |
|||
.then(function (result) { |
|||
finishSaving(result); |
|||
}); |
|||
} |
|||
} |
|||
|
|||
function finishSaving(result) { |
|||
abp.notify.success(l('SuccessfullySaved')); |
|||
abp.ui.clearBusy(); |
|||
location.href = "/CmsKit/Pages/"; |
|||
} |
|||
}); |
|||
@ -0,0 +1,22 @@ |
|||
@model TagEditorViewComponent.TagEditorViewModel |
|||
|
|||
@using Volo.CmsKit.Admin.Web.Pages.CmsKit.Tags.Components.TagEditor |
|||
@using Volo.CmsKit.Localization |
|||
@using Microsoft.Extensions.Localization |
|||
|
|||
@inject IStringLocalizer<CmsKitResource> L |
|||
|
|||
<form class="tag-editor-form" data-entity-id="@Model.EntityId" data-entity-type="@Model.EntityType"> |
|||
|
|||
<div class="form-group"> |
|||
<label>@L["Tags"]</label> |
|||
<input name="tags" value="@string.Join(',', Model.Tags.Select(s => s.Name))" class="form-control"/> |
|||
</div> |
|||
|
|||
@if (Model.DisplaySubmitButton) |
|||
{ |
|||
<abp-form-row> |
|||
<abp-button type="submit" text="@L["Submit"]" /> |
|||
</abp-form-row> |
|||
} |
|||
</form> |
|||
@ -0,0 +1,49 @@ |
|||
using Microsoft.AspNetCore.Mvc; |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Threading.Tasks; |
|||
using Volo.Abp.AspNetCore.Mvc; |
|||
using Volo.Abp.AspNetCore.Mvc.UI.Widgets; |
|||
using Volo.CmsKit.Tags; |
|||
|
|||
namespace Volo.CmsKit.Admin.Web.Pages.CmsKit.Tags.Components.TagEditor |
|||
{ |
|||
[Widget( |
|||
ScriptFiles = new[] |
|||
{ |
|||
"/Pages/CmsKit/Tags/Components/TagEditor/default.js" |
|||
})] |
|||
public class TagEditorViewComponent : AbpViewComponent |
|||
{ |
|||
protected ITagAppService TagAppService { get; } |
|||
|
|||
public TagEditorViewComponent(ITagAppService tagAppService) |
|||
{ |
|||
TagAppService = tagAppService; |
|||
} |
|||
|
|||
public async Task<IViewComponentResult> InvokeAsync(string entityType, string entityId, bool displaySubmitButton = true) |
|||
{ |
|||
var tags = |
|||
entityId.IsNullOrWhiteSpace() ? |
|||
new List<TagDto>() : |
|||
await TagAppService.GetAllRelatedTagsAsync(entityType, entityId); |
|||
|
|||
return View("~/Pages/CmsKit/Tags/Components/TagEditor/Default.cshtml", new TagEditorViewModel |
|||
{ |
|||
EntityId = entityId, |
|||
EntityType = entityType, |
|||
Tags = tags, |
|||
DisplaySubmitButton = displaySubmitButton |
|||
}); |
|||
} |
|||
|
|||
public class TagEditorViewModel |
|||
{ |
|||
public string EntityType { get; set; } |
|||
public string EntityId { get; set; } |
|||
public List<TagDto> Tags { get; set; } |
|||
public bool DisplaySubmitButton { get; set; } |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,26 @@ |
|||
$(function () { |
|||
|
|||
var $tagEditorForms = $('.tag-editor-form'); |
|||
|
|||
$tagEditorForms.on('submit', function (e) { |
|||
e.preventDefault(); |
|||
|
|||
var $form = $(e.currentTarget); |
|||
|
|||
if ($form.valid()) { |
|||
|
|||
abp.ui.setBusy(); |
|||
|
|||
var entityId = $form.data('entity-id'); |
|||
var entityType = $form.data('entity-type'); |
|||
var tags = $form.find('input').val().split(","); |
|||
|
|||
volo.cmsKit.admin.tags.entityTagAdmin |
|||
.setEntityTags({ |
|||
entityId: entityId, |
|||
entityType: entityType, |
|||
tags: tags |
|||
}) |
|||
} |
|||
}) |
|||
}) |
|||
@ -0,0 +1,23 @@ |
|||
@page |
|||
@using Microsoft.AspNetCore.Mvc.Localization |
|||
@using Volo.CmsKit.Admin.Web.Pages.CmsKit.Tags |
|||
@using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Modal |
|||
@using Volo.CmsKit.Localization |
|||
|
|||
@inject IHtmlLocalizer<CmsKitResource> L |
|||
|
|||
@model CreateModalModel |
|||
|
|||
@{ |
|||
Layout = null; |
|||
} |
|||
|
|||
<abp-dynamic-form abp-model="ViewModel" asp-page="/CmsKit/Tags/CreateModal"> |
|||
<abp-modal> |
|||
<abp-modal-header title="@L["New"].Value"></abp-modal-header> |
|||
<abp-modal-body> |
|||
<abp-form-content/> |
|||
</abp-modal-body> |
|||
<abp-modal-footer buttons="@(AbpModalButtons.Cancel | AbpModalButtons.Save)"></abp-modal-footer> |
|||
</abp-modal> |
|||
</abp-dynamic-form> |
|||
@ -0,0 +1,58 @@ |
|||
using AutoMapper; |
|||
using Microsoft.AspNetCore.Mvc; |
|||
using Microsoft.AspNetCore.Mvc.Rendering; |
|||
using System.Collections.Generic; |
|||
using System.ComponentModel.DataAnnotations; |
|||
using System.Linq; |
|||
using System.Threading.Tasks; |
|||
using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form; |
|||
using Volo.Abp.Validation; |
|||
using Volo.CmsKit.Admin.Tags; |
|||
using Volo.CmsKit.Tags; |
|||
|
|||
namespace Volo.CmsKit.Admin.Web.Pages.CmsKit.Tags |
|||
{ |
|||
public class CreateModalModel : CmsKitAdminPageModel |
|||
{ |
|||
protected ITagAdminAppService TagAdminAppService { get; } |
|||
|
|||
[BindProperty] |
|||
public TagCreateViewModel ViewModel { get; set; } |
|||
|
|||
public List<SelectListItem> TagDefinitions { get; set; } |
|||
|
|||
public CreateModalModel(ITagAdminAppService tagAdminAppService) |
|||
{ |
|||
TagAdminAppService = tagAdminAppService; |
|||
} |
|||
|
|||
public async Task OnGetAsync() |
|||
{ |
|||
var definitions = await TagAdminAppService.GetTagDefinitionsAsync(); |
|||
|
|||
TagDefinitions = definitions.Select(s => new SelectListItem(s.DisplayName, s.EntityType)).ToList(); |
|||
} |
|||
|
|||
public async Task<IActionResult> OnPostAsync() |
|||
{ |
|||
var tagCreateDto = ObjectMapper.Map<TagCreateViewModel, TagCreateDto>(ViewModel); |
|||
|
|||
await TagAdminAppService.CreateAsync(tagCreateDto); |
|||
|
|||
return NoContent(); |
|||
} |
|||
|
|||
[AutoMap(typeof(TagCreateDto), ReverseMap = true)] |
|||
public class TagCreateViewModel |
|||
{ |
|||
[DynamicMaxLength(typeof(TagConsts), nameof(TagConsts.MaxEntityTypeLength))] |
|||
[Required] |
|||
[SelectItems(nameof(TagDefinitions))] |
|||
public string EntityType { get; set; } |
|||
|
|||
[DynamicMaxLength(typeof(TagConsts), nameof(TagConsts.MaxNameLength))] |
|||
[Required] |
|||
public string Name { get; set; } |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,24 @@ |
|||
@page |
|||
@using Microsoft.AspNetCore.Mvc.Localization |
|||
@using Volo.CmsKit.Admin.Web.Pages |
|||
@using Volo.CmsKit.Admin.Web.Pages.CmsKit.Tags |
|||
@using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Modal |
|||
@using Volo.CmsKit.Localization |
|||
|
|||
@inject IHtmlLocalizer<CmsKitResource> L |
|||
@model EditModalModel |
|||
|
|||
@{ |
|||
Layout = null; |
|||
} |
|||
|
|||
<abp-dynamic-form abp-model="ViewModel" asp-page="/CmsKit/Tags/EditModal"> |
|||
<abp-modal> |
|||
<abp-modal-header title="@L["Update"].Value"></abp-modal-header> |
|||
<abp-modal-body> |
|||
<abp-input asp-for="Id" /> |
|||
<abp-form-content /> |
|||
</abp-modal-body> |
|||
<abp-modal-footer buttons="@(AbpModalButtons.Cancel|AbpModalButtons.Save)"></abp-modal-footer> |
|||
</abp-modal> |
|||
</abp-dynamic-form> |
|||
@ -0,0 +1,54 @@ |
|||
using AutoMapper; |
|||
using Microsoft.AspNetCore.Mvc; |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.ComponentModel.DataAnnotations; |
|||
using System.Linq; |
|||
using System.Text; |
|||
using System.Threading.Tasks; |
|||
using Volo.Abp.Validation; |
|||
using Volo.CmsKit.Admin.Tags; |
|||
using Volo.CmsKit.Tags; |
|||
|
|||
namespace Volo.CmsKit.Admin.Web.Pages.CmsKit.Tags |
|||
{ |
|||
public class EditModalModel : CmsKitAdminPageModel |
|||
{ |
|||
protected ITagAdminAppService TagAdminAppService { get; } |
|||
|
|||
[HiddenInput] |
|||
[BindProperty(SupportsGet = true)] |
|||
public Guid Id { get; set; } |
|||
|
|||
[BindProperty] |
|||
public TagEditViewModel ViewModel { get; set; } |
|||
|
|||
public EditModalModel(ITagAdminAppService tagAdminAppService) |
|||
{ |
|||
this.TagAdminAppService = tagAdminAppService; |
|||
} |
|||
|
|||
public async Task OnGetAsync() |
|||
{ |
|||
var dto = await TagAdminAppService.GetAsync(Id); |
|||
|
|||
ViewModel = ObjectMapper.Map<TagDto, TagEditViewModel>(dto); |
|||
} |
|||
|
|||
public async Task<IActionResult> OnPostAsync() |
|||
{ |
|||
var tagDto = ObjectMapper.Map<TagEditViewModel, TagUpdateDto>(ViewModel); |
|||
await TagAdminAppService.UpdateAsync(Id, tagDto); |
|||
return NoContent(); |
|||
} |
|||
|
|||
[AutoMap(typeof(TagDto))] |
|||
[AutoMap(typeof(TagUpdateDto), ReverseMap = true)] |
|||
public class TagEditViewModel |
|||
{ |
|||
[Required] |
|||
[DynamicMaxLength(typeof(TagConsts), nameof(TagConsts.MaxNameLength))] |
|||
public string Name { get; set; } |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,38 @@ |
|||
@page |
|||
|
|||
@using Volo.CmsKit.Admin.Web.Pages |
|||
@using Volo.CmsKit.Admin.Web.Pages.CmsKit.Tags |
|||
@using Volo.CmsKit.Admin.Web.Menus |
|||
@using Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Pages.Shared.Components.AbpPageToolbar |
|||
@using Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Pages.Shared.Components.AbpPageSearchBox |
|||
|
|||
@inherits CmsKitAdminPageBase |
|||
|
|||
@model IndexModel |
|||
|
|||
@{ |
|||
PageLayout.Content.Title = L["Tags"].Value; |
|||
PageLayout.Content.BreadCrumb.Add(L["Menu:CMS"].Value); |
|||
PageLayout.Content.MenuItemName = CmsKitAdminMenus.Tags.TagsMenu; |
|||
} |
|||
@section scripts { |
|||
<abp-script src="/Pages/CmsKit/Tags/Index.js" /> |
|||
} |
|||
|
|||
@section content_toolbar { |
|||
@await Component.InvokeAsync(typeof(AbpPageToolbarViewComponent), new { pageName = typeof(IndexModel).FullName }) |
|||
} |
|||
|
|||
<div id="CmsKitTagsWrapper"> |
|||
<abp-card> |
|||
<abp-card-body> |
|||
<abp-row> |
|||
<abp-column> |
|||
@await Component.InvokeAsync(typeof(AbpPageSearchBoxViewComponent)) |
|||
</abp-column> |
|||
</abp-row> |
|||
</abp-card-body> |
|||
</abp-card> |
|||
<abp-table striped-rows="true" id="TagsTable"></abp-table> |
|||
</div> |
|||
|
|||
@ -0,0 +1,8 @@ |
|||
using Volo.Abp.AspNetCore.Mvc.UI.RazorPages; |
|||
|
|||
namespace Volo.CmsKit.Admin.Web.Pages.CmsKit.Tags |
|||
{ |
|||
public class IndexModel : CmsKitAdminPageModel |
|||
{ |
|||
} |
|||
} |
|||
@ -0,0 +1,83 @@ |
|||
$(function () { |
|||
var l = abp.localization.getResource("CmsKit"); |
|||
|
|||
var createModal = new abp.ModalManager(abp.appPath + "CmsKit/Tags/CreateModal"); |
|||
var updateModal = new abp.ModalManager(abp.appPath + "CmsKit/Tags/EditModal"); |
|||
|
|||
var service = volo.cmsKit.admin.tags.tagAdmin; |
|||
|
|||
var getFilter = function () { |
|||
return { |
|||
filter: $('#CmsKitTagsWrapper input.page-search-filter-text').val() |
|||
}; |
|||
}; |
|||
|
|||
let dataTable = $("#TagsTable").DataTable(abp.libs.datatables.normalizeConfiguration({ |
|||
processing: true, |
|||
serverSide: true, |
|||
paging: true, |
|||
searching: false, |
|||
autoWidth: false, |
|||
scrollCollapse: true, |
|||
scrollX: true, |
|||
ordering: false, |
|||
ajax: abp.libs.datatables.createAjax(service.getList, getFilter), |
|||
columnDefs: [ |
|||
{ |
|||
title: l("Actions"), |
|||
rowAction: { |
|||
items: [ |
|||
{ |
|||
text: l("Edit"), |
|||
visible: abp.auth.isGranted('CmsKit.Tags.Update'), |
|||
action: function (data) { |
|||
updateModal.open({ id: data.record.id }); |
|||
} |
|||
}, |
|||
{ |
|||
text: l("Delete"), |
|||
visible: abp.auth.isGranted('CmsKit.Tags.Delete'), |
|||
confirmMessage: function (data) { |
|||
return l("TagDeletionConfirmationMessage", data.record.name) |
|||
}, |
|||
action: function (data) { |
|||
service |
|||
.delete(data.record.id) |
|||
.then(function () { |
|||
abp.notify.info(l("SuccessfullyDeleted")); |
|||
dataTable.ajax.reload(null, false); |
|||
}); |
|||
} |
|||
} |
|||
] |
|||
} |
|||
}, |
|||
{ |
|||
title: l("EntityType"), |
|||
data: "entityType" |
|||
}, |
|||
{ |
|||
title: l("Name"), |
|||
data: "name" |
|||
} |
|||
] |
|||
})); |
|||
|
|||
$('#CmsKitTagsWrapper form.page-search-form').on('submit', function (e) { |
|||
e.preventDefault(); |
|||
dataTable.ajax.reload(); |
|||
}); |
|||
|
|||
$('#AbpContentToolbar button[name=NewButton]').on('click', function (e) { |
|||
e.preventDefault(); |
|||
createModal.open(); |
|||
}); |
|||
|
|||
createModal.onResult(function () { |
|||
dataTable.ajax.reload(); |
|||
}); |
|||
|
|||
updateModal.onResult(function () { |
|||
dataTable.ajax.reload(); |
|||
}); |
|||
}); |
|||
@ -0,0 +1,4 @@ |
|||
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers |
|||
@addTagHelper *, Volo.Abp.AspNetCore.Mvc.UI |
|||
@addTagHelper *, Volo.Abp.AspNetCore.Mvc.UI.Bootstrap |
|||
@addTagHelper *, Volo.Abp.AspNetCore.Mvc.UI.Bundling |
|||
@ -0,0 +1,20 @@ |
|||
using Microsoft.AspNetCore.Mvc.Razor.Internal; |
|||
using Microsoft.Extensions.Localization; |
|||
using System.Threading.Tasks; |
|||
using Volo.Abp.AspNetCore.Mvc.UI.Layout; |
|||
using Volo.CmsKit.Localization; |
|||
|
|||
namespace Volo.CmsKit.Admin.Web.Pages |
|||
{ |
|||
public class CmsKitAdminPageBase : Microsoft.AspNetCore.Mvc.RazorPages.Page |
|||
{ |
|||
[RazorInject] public IStringLocalizer<CmsKitResource> L { get; set; } |
|||
|
|||
[RazorInject] public IPageLayout PageLayout { get; set; } |
|||
|
|||
public override Task ExecuteAsync() |
|||
{ |
|||
return Task.CompletedTask; // Will be overriden by razor pages. (.cshtml)
|
|||
} |
|||
} |
|||
} |
|||
@ -1,10 +1,11 @@ |
|||
@page "/blogs/{blogSlug}" |
|||
@page |
|||
|
|||
@using Volo.CmsKit.Public.Web.Pages |
|||
@using Volo.CmsKit.Public.Web.Pages.Public.CmsKit.Blogs |
|||
|
|||
@inherits CmsKitPublicPageBase |
|||
|
|||
@model Volo.CmsKit.Public.Web.Pages.CmsKit.Blogs.IndexModel |
|||
@model IndexModel |
|||
|
|||
<abp-row id="blogs-container"> |
|||
@foreach (var blog in Model.Blogs.Items) |
|||
Loading…
Reference in new issue