├── .github ├── FUNDING.yml └── ISSUE_TEMPLATE │ ├── bug_report.md │ └── feature_request.md ├── .gitignore ├── .vscode └── settings.json ├── CODE_OF_CONDUCT.md ├── DatatableJS.Data.UnitTest ├── DataTests.cs └── DatatableJS.Data.UnitTest.csproj ├── DatatableJS.Data ├── Builders │ └── ExpressionBuilder.cs ├── DatatableExtensions.cs ├── DatatableJS.Data.csproj └── Models │ ├── DataRequest.cs │ ├── DataResult.cs │ └── FilterDef.cs ├── DatatableJS.Net ├── Builders │ ├── CallbackBuilder.cs │ ├── ColReorderBuilder.cs │ ├── ColumnBuilder.cs │ ├── FilterBuilder.cs │ ├── GridBuilder.cs │ ├── LanguageBuilder.cs │ └── OrderBuilder.cs ├── DatatableJS.Net.csproj ├── Definitions │ ├── ColumnDefinition.cs │ ├── FilterDefinition.cs │ └── OrderDefinition.cs ├── Exceptions │ └── ColumnNotFoundException.cs ├── JSHelper.cs ├── Models │ ├── CallbackModel.cs │ ├── ColReorderModel.cs │ ├── Command.cs │ ├── Enums.cs │ └── LanguageModel.cs └── Utilities │ └── ExpressionHelpers.cs ├── DatatableJS.sln ├── DatatableJS ├── Builders │ ├── CallbackBuilder.cs │ ├── ColReorderBuilder.cs │ ├── ColumnBuilder.cs │ ├── FilterBuilder.cs │ ├── GridBuilder.cs │ ├── LanguageBuilder.cs │ └── OrderBuilder.cs ├── DatatableJS.csproj ├── Definitions │ └── ColumnDefinition.cs ├── Exceptions │ └── ColumnNotFoundException.cs ├── Helpers │ ├── AriaHelper.cs │ ├── CallbackHelper.cs │ ├── CaptionsHelper.cs │ ├── ColReorderHelper.cs │ ├── ColumnsHelper.cs │ ├── CommandHelper.cs │ ├── CommandsHelper.cs │ ├── CommonHelpers.cs │ ├── DataSourceHelper.cs │ ├── FiltersHelper.cs │ ├── FixedColumnsHelper.cs │ ├── GridHelper.cs │ ├── LanguageHelper.cs │ ├── LengthMenuHelper.cs │ ├── OrdersHelper.cs │ ├── PaginateHelper.cs │ └── RenderHelper.cs ├── JSHelper.cs ├── Models │ ├── CallbackModel.cs │ ├── CaptionsModel.cs │ ├── ColReorderModel.cs │ ├── ColumnModel.cs │ ├── Command.cs │ ├── DataSourceModel.cs │ ├── Enums.cs │ ├── FilterModel.cs │ ├── FixedColumnsModel.cs │ ├── GridModel.cs │ ├── LanguageModel.cs │ ├── LengthMenuModel.cs │ └── OrderModel.cs └── Utilities │ └── ExpressionHelpers.cs ├── LICENSE.md ├── README.md ├── _config.yml ├── appveyor.yml └── datatable-js.png /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: [ekondur] 2 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behavior: 15 | 1. Go to '...' 16 | 2. Click on '....' 17 | 3. Scroll down to '....' 18 | 4. See error 19 | 20 | **Expected behavior** 21 | A clear and concise description of what you expected to happen. 22 | 23 | **Screenshots** 24 | If applicable, add screenshots to help explain your problem. 25 | 26 | **Desktop (please complete the following information):** 27 | - OS: [e.g. iOS] 28 | - Browser [e.g. chrome, safari] 29 | - Version [e.g. 22] 30 | 31 | **Smartphone (please complete the following information):** 32 | - Device: [e.g. iPhone6] 33 | - OS: [e.g. iOS8.1] 34 | - Browser [e.g. stock browser, safari] 35 | - Version [e.g. 22] 36 | 37 | **Additional context** 38 | Add any other context about the problem here. 39 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | ## 4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore 5 | 6 | # User-specific files 7 | *.rsuser 8 | *.suo 9 | *.user 10 | *.userosscache 11 | *.sln.docstates 12 | 13 | # User-specific files (MonoDevelop/Xamarin Studio) 14 | *.userprefs 15 | 16 | # Build results 17 | [Dd]ebug/ 18 | [Dd]ebugPublic/ 19 | [Rr]elease/ 20 | [Rr]eleases/ 21 | x64/ 22 | x86/ 23 | [Aa][Rr][Mm]/ 24 | [Aa][Rr][Mm]64/ 25 | bld/ 26 | [Bb]in/ 27 | [Oo]bj/ 28 | [Ll]og/ 29 | 30 | # Visual Studio 2015/2017 cache/options directory 31 | .vs/ 32 | # Uncomment if you have tasks that create the project's static files in wwwroot 33 | #wwwroot/ 34 | 35 | # Visual Studio 2017 auto generated files 36 | Generated\ Files/ 37 | 38 | # MSTest test Results 39 | [Tt]est[Rr]esult*/ 40 | [Bb]uild[Ll]og.* 41 | 42 | # NUNIT 43 | *.VisualState.xml 44 | TestResult.xml 45 | 46 | # Build Results of an ATL Project 47 | [Dd]ebugPS/ 48 | [Rr]eleasePS/ 49 | dlldata.c 50 | 51 | # Benchmark Results 52 | BenchmarkDotNet.Artifacts/ 53 | 54 | # .NET Core 55 | project.lock.json 56 | project.fragment.lock.json 57 | artifacts/ 58 | 59 | # StyleCop 60 | StyleCopReport.xml 61 | 62 | # Files built by Visual Studio 63 | *_i.c 64 | *_p.c 65 | *_h.h 66 | *.ilk 67 | *.meta 68 | *.obj 69 | *.iobj 70 | *.pch 71 | *.pdb 72 | *.ipdb 73 | *.pgc 74 | *.pgd 75 | *.rsp 76 | *.sbr 77 | *.tlb 78 | *.tli 79 | *.tlh 80 | *.tmp 81 | *.tmp_proj 82 | *_wpftmp.csproj 83 | *.log 84 | *.vspscc 85 | *.vssscc 86 | .builds 87 | *.pidb 88 | *.svclog 89 | *.scc 90 | 91 | # Chutzpah Test files 92 | _Chutzpah* 93 | 94 | # Visual C++ cache files 95 | ipch/ 96 | *.aps 97 | *.ncb 98 | *.opendb 99 | *.opensdf 100 | *.sdf 101 | *.cachefile 102 | *.VC.db 103 | *.VC.VC.opendb 104 | 105 | # Visual Studio profiler 106 | *.psess 107 | *.vsp 108 | *.vspx 109 | *.sap 110 | 111 | # Visual Studio Trace Files 112 | *.e2e 113 | 114 | # TFS 2012 Local Workspace 115 | $tf/ 116 | 117 | # Guidance Automation Toolkit 118 | *.gpState 119 | 120 | # ReSharper is a .NET coding add-in 121 | _ReSharper*/ 122 | *.[Rr]e[Ss]harper 123 | *.DotSettings.user 124 | 125 | # JustCode is a .NET coding add-in 126 | .JustCode 127 | 128 | # TeamCity is a build add-in 129 | _TeamCity* 130 | 131 | # DotCover is a Code Coverage Tool 132 | *.dotCover 133 | 134 | # AxoCover is a Code Coverage Tool 135 | .axoCover/* 136 | !.axoCover/settings.json 137 | 138 | # Visual Studio code coverage results 139 | *.coverage 140 | *.coveragexml 141 | 142 | # NCrunch 143 | _NCrunch_* 144 | .*crunch*.local.xml 145 | nCrunchTemp_* 146 | 147 | # MightyMoose 148 | *.mm.* 149 | AutoTest.Net/ 150 | 151 | # Web workbench (sass) 152 | .sass-cache/ 153 | 154 | # Installshield output folder 155 | [Ee]xpress/ 156 | 157 | # DocProject is a documentation generator add-in 158 | DocProject/buildhelp/ 159 | DocProject/Help/*.HxT 160 | DocProject/Help/*.HxC 161 | DocProject/Help/*.hhc 162 | DocProject/Help/*.hhk 163 | DocProject/Help/*.hhp 164 | DocProject/Help/Html2 165 | DocProject/Help/html 166 | 167 | # Click-Once directory 168 | publish/ 169 | 170 | # Publish Web Output 171 | *.[Pp]ublish.xml 172 | *.azurePubxml 173 | # Note: Comment the next line if you want to checkin your web deploy settings, 174 | # but database connection strings (with potential passwords) will be unencrypted 175 | *.pubxml 176 | *.publishproj 177 | 178 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 179 | # checkin your Azure Web App publish settings, but sensitive information contained 180 | # in these scripts will be unencrypted 181 | PublishScripts/ 182 | 183 | # NuGet Packages 184 | *.nupkg 185 | # The packages folder can be ignored because of Package Restore 186 | **/[Pp]ackages/* 187 | # except build/, which is used as an MSBuild target. 188 | !**/[Pp]ackages/build/ 189 | # Uncomment if necessary however generally it will be regenerated when needed 190 | #!**/[Pp]ackages/repositories.config 191 | # NuGet v3's project.json files produces more ignorable files 192 | *.nuget.props 193 | *.nuget.targets 194 | 195 | # Microsoft Azure Build Output 196 | csx/ 197 | *.build.csdef 198 | 199 | # Microsoft Azure Emulator 200 | ecf/ 201 | rcf/ 202 | 203 | # Windows Store app package directories and files 204 | AppPackages/ 205 | BundleArtifacts/ 206 | Package.StoreAssociation.xml 207 | _pkginfo.txt 208 | *.appx 209 | 210 | # Visual Studio cache files 211 | # files ending in .cache can be ignored 212 | *.[Cc]ache 213 | # but keep track of directories ending in .cache 214 | !?*.[Cc]ache/ 215 | 216 | # Others 217 | ClientBin/ 218 | ~$* 219 | *~ 220 | *.dbmdl 221 | *.dbproj.schemaview 222 | *.jfm 223 | *.pfx 224 | *.publishsettings 225 | orleans.codegen.cs 226 | 227 | # Including strong name files can present a security risk 228 | # (https://github.com/github/gitignore/pull/2483#issue-259490424) 229 | #*.snk 230 | 231 | # Since there are multiple workflows, uncomment next line to ignore bower_components 232 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 233 | #bower_components/ 234 | 235 | # RIA/Silverlight projects 236 | Generated_Code/ 237 | 238 | # Backup & report files from converting an old project file 239 | # to a newer Visual Studio version. Backup files are not needed, 240 | # because we have git ;-) 241 | _UpgradeReport_Files/ 242 | Backup*/ 243 | UpgradeLog*.XML 244 | UpgradeLog*.htm 245 | ServiceFabricBackup/ 246 | *.rptproj.bak 247 | 248 | # SQL Server files 249 | *.mdf 250 | *.ldf 251 | *.ndf 252 | 253 | # Business Intelligence projects 254 | *.rdl.data 255 | *.bim.layout 256 | *.bim_*.settings 257 | *.rptproj.rsuser 258 | *- Backup*.rdl 259 | 260 | # Microsoft Fakes 261 | FakesAssemblies/ 262 | 263 | # GhostDoc plugin setting file 264 | *.GhostDoc.xml 265 | 266 | # Node.js Tools for Visual Studio 267 | .ntvs_analysis.dat 268 | node_modules/ 269 | 270 | # Visual Studio 6 build log 271 | *.plg 272 | 273 | # Visual Studio 6 workspace options file 274 | *.opt 275 | 276 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 277 | *.vbw 278 | 279 | # Visual Studio LightSwitch build output 280 | **/*.HTMLClient/GeneratedArtifacts 281 | **/*.DesktopClient/GeneratedArtifacts 282 | **/*.DesktopClient/ModelManifest.xml 283 | **/*.Server/GeneratedArtifacts 284 | **/*.Server/ModelManifest.xml 285 | _Pvt_Extensions 286 | 287 | # Paket dependency manager 288 | .paket/paket.exe 289 | paket-files/ 290 | 291 | # FAKE - F# Make 292 | .fake/ 293 | 294 | # JetBrains Rider 295 | .idea/ 296 | *.sln.iml 297 | 298 | # CodeRush personal settings 299 | .cr/personal 300 | 301 | # Python Tools for Visual Studio (PTVS) 302 | __pycache__/ 303 | *.pyc 304 | 305 | # Cake - Uncomment if you are using it 306 | # tools/** 307 | # !tools/packages.config 308 | 309 | # Tabs Studio 310 | *.tss 311 | 312 | # Telerik's JustMock configuration file 313 | *.jmconfig 314 | 315 | # BizTalk build output 316 | *.btp.cs 317 | *.btm.cs 318 | *.odx.cs 319 | *.xsd.cs 320 | 321 | # OpenCover UI analysis results 322 | OpenCover/ 323 | 324 | # Azure Stream Analytics local run output 325 | ASALocalRun/ 326 | 327 | # MSBuild Binary and Structured Log 328 | *.binlog 329 | 330 | # NVidia Nsight GPU debugger configuration file 331 | *.nvuser 332 | 333 | # MFractors (Xamarin productivity tool) working folder 334 | .mfractor/ 335 | 336 | # Local History for Visual Studio 337 | .localhistory/ 338 | 339 | # BeatPulse healthcheck temp database 340 | healthchecksdb 341 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | {} -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | In the interest of fostering an open and welcoming environment, we as 6 | contributors and maintainers pledge to making participation in our project and 7 | our community a harassment-free experience for everyone, regardless of age, body 8 | size, disability, ethnicity, sex characteristics, gender identity and expression, 9 | level of experience, education, socio-economic status, nationality, personal 10 | appearance, race, religion, or sexual identity and orientation. 11 | 12 | ## Our Standards 13 | 14 | Examples of behavior that contributes to creating a positive environment 15 | include: 16 | 17 | * Using welcoming and inclusive language 18 | * Being respectful of differing viewpoints and experiences 19 | * Gracefully accepting constructive criticism 20 | * Focusing on what is best for the community 21 | * Showing empathy towards other community members 22 | 23 | Examples of unacceptable behavior by participants include: 24 | 25 | * The use of sexualized language or imagery and unwelcome sexual attention or 26 | advances 27 | * Trolling, insulting/derogatory comments, and personal or political attacks 28 | * Public or private harassment 29 | * Publishing others' private information, such as a physical or electronic 30 | address, without explicit permission 31 | * Other conduct which could reasonably be considered inappropriate in a 32 | professional setting 33 | 34 | ## Our Responsibilities 35 | 36 | Project maintainers are responsible for clarifying the standards of acceptable 37 | behavior and are expected to take appropriate and fair corrective action in 38 | response to any instances of unacceptable behavior. 39 | 40 | Project maintainers have the right and responsibility to remove, edit, or 41 | reject comments, commits, code, wiki edits, issues, and other contributions 42 | that are not aligned to this Code of Conduct, or to ban temporarily or 43 | permanently any contributor for other behaviors that they deem inappropriate, 44 | threatening, offensive, or harmful. 45 | 46 | ## Scope 47 | 48 | This Code of Conduct applies both within project spaces and in public spaces 49 | when an individual is representing the project or its community. Examples of 50 | representing a project or community include using an official project e-mail 51 | address, posting via an official social media account, or acting as an appointed 52 | representative at an online or offline event. Representation of a project may be 53 | further defined and clarified by project maintainers. 54 | 55 | ## Enforcement 56 | 57 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 58 | reported by contacting the project team at emrahkondur@hotmail.com. All 59 | complaints will be reviewed and investigated and will result in a response that 60 | is deemed necessary and appropriate to the circumstances. The project team is 61 | obligated to maintain confidentiality with regard to the reporter of an incident. 62 | Further details of specific enforcement policies may be posted separately. 63 | 64 | Project maintainers who do not follow or enforce the Code of Conduct in good 65 | faith may face temporary or permanent repercussions as determined by other 66 | members of the project's leadership. 67 | 68 | ## Attribution 69 | 70 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, 71 | available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html 72 | 73 | [homepage]: https://www.contributor-covenant.org 74 | 75 | For answers to common questions about this code of conduct, see 76 | https://www.contributor-covenant.org/faq 77 | -------------------------------------------------------------------------------- /DatatableJS.Data.UnitTest/DataTests.cs: -------------------------------------------------------------------------------- 1 | using NUnit.Framework; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | 5 | namespace DatatableJS.Data.UnitTest 6 | { 7 | [TestFixture] 8 | public class Tests 9 | { 10 | IQueryable _list; 11 | DataRequest _request; 12 | 13 | [SetUp] 14 | public void Setup() 15 | { 16 | _list = new List 17 | { 18 | new Person { Name = "Jon", Age = 1}, 19 | new Person { Name = "Arya", Age = 1 }, 20 | new Person { Name = "Arya", Age = 2 } 21 | }.AsQueryable(); 22 | 23 | var _columns = new List { 24 | new Column {data = "Name", name = "Name", orderable = true, searchable = true, search = new Search()}, 25 | new Column {data = "Age", name = "Age", orderable = true, searchable = true, search = new Search()}, 26 | }; 27 | 28 | _request = new DataRequest { columns = _columns, draw = 1, length = 10 }; 29 | } 30 | 31 | [Test] 32 | public void ToDataResult_WhenFilterWithNameDoesNotContain_ReturnsListCountZero() 33 | { 34 | _request.filters.Add(new Filter { Field = "Name", Operand = Operand.Contains, Value = "Jon" }); 35 | var result = _list.ToDataResult(_request); 36 | 37 | Assert.That(result.data.Count, Is.EqualTo(1)); 38 | } 39 | 40 | [Test] 41 | public void ToDataResult_WhenSortingByNameAndAge() 42 | { 43 | _request.order.Add(new Order 44 | { 45 | column = 0, 46 | dir = "asc" 47 | }); 48 | _request.order.Add(new Order 49 | { 50 | column = 1, 51 | dir = "asc" 52 | }); 53 | var result = _list.ToDataResult(_request); 54 | 55 | Assert.That(result.data[0].Name, Is.EqualTo("Arya")); 56 | Assert.That(result.data[0].Age, Is.EqualTo(1)); 57 | Assert.That(result.data[1].Name, Is.EqualTo("Arya")); 58 | Assert.That(result.data[1].Age, Is.EqualTo(2)); 59 | } 60 | } 61 | 62 | public class Person 63 | { 64 | public string Name { get; set; } 65 | public int Age { get; set; } 66 | } 67 | } -------------------------------------------------------------------------------- /DatatableJS.Data.UnitTest/DatatableJS.Data.UnitTest.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net5.0 5 | 6 | false 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /DatatableJS.Data/Builders/ExpressionBuilder.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel; 4 | using System.Linq.Expressions; 5 | using System.Reflection; 6 | 7 | namespace DatatableJS.Data 8 | { 9 | internal static class ExpressionBuilder 10 | { 11 | private static readonly MethodInfo containsMethod = typeof(string).GetMethod("Contains", new Type[] { typeof(string) }); 12 | private static readonly MethodInfo startsWithMethod = typeof(string).GetMethod("StartsWith", new Type[] { typeof(string) }); 13 | private static readonly MethodInfo endsWithMethod = typeof(string).GetMethod("EndsWith", new Type[] { typeof(string) }); 14 | 15 | internal static Expression> GetExpression(FilterDef filter) 16 | { 17 | if (filter == null) 18 | { 19 | return null; 20 | } 21 | 22 | ParameterExpression param = Expression.Parameter(typeof(T), "t"); 23 | var exp = GetExpression(param, filter); 24 | if (exp == null) 25 | { 26 | return null; 27 | } 28 | return Expression.Lambda>(exp, param); 29 | } 30 | 31 | private static Expression GetExpression(ParameterExpression param, FilterDef filter) 32 | { 33 | MemberExpression member = Expression.Property(param, filter.Field); 34 | var converter = TypeDescriptor.GetConverter(member.Type); 35 | if (!converter.IsValid(filter.Value)) 36 | { 37 | return null; 38 | } 39 | var propertyValue = converter.ConvertFromInvariantString(filter.Value); 40 | ConstantExpression constant = Expression.Constant(propertyValue, member.Type); 41 | 42 | switch (filter.Operand) 43 | { 44 | case Operand.Equal: 45 | return Expression.Equal(member, constant); 46 | 47 | case Operand.NotEqual: 48 | return Expression.NotEqual(member, constant); 49 | 50 | case Operand.GreaterThan: 51 | return Expression.GreaterThan(member, constant); 52 | 53 | case Operand.GreaterThanOrEqual: 54 | return Expression.GreaterThanOrEqual(member, constant); 55 | 56 | case Operand.LessThan: 57 | return Expression.LessThan(member, constant); 58 | 59 | case Operand.LessThanOrEqual: 60 | return Expression.LessThanOrEqual(member, constant); 61 | 62 | case Operand.Contains: 63 | return Expression.Call(member, containsMethod, constant); 64 | 65 | case Operand.StartsWith: 66 | return Expression.Call(member, startsWithMethod, constant); 67 | 68 | case Operand.EndsWith: 69 | return Expression.Call(member, endsWithMethod, constant); 70 | default: 71 | return null; 72 | } 73 | } 74 | 75 | internal static Expression> GetExpression(IList filters) 76 | { 77 | if (filters.Count == 0) 78 | { 79 | return null; 80 | } 81 | 82 | ParameterExpression param = Expression.Parameter(typeof(T), "t"); 83 | Expression exp = null; 84 | 85 | foreach (var filter in filters) 86 | { 87 | var isAnd = filter.Operator == Operator.And; 88 | var expin = GetExpression(param, filter); 89 | if (expin != null) 90 | { 91 | if (exp == null) 92 | { 93 | exp = expin; 94 | } 95 | else 96 | { 97 | exp = isAnd ? Expression.And(exp, expin) : Expression.Or(exp, expin); 98 | } 99 | } 100 | else 101 | { 102 | if (exp != null) 103 | { 104 | exp = isAnd ? Expression.And(exp, Expression.Constant(false)) : Expression.Or(exp, Expression.Constant(false)); 105 | } 106 | else 107 | { 108 | exp = isAnd ? Expression.And(Expression.Constant(false), Expression.Constant(false)) : Expression.Or(Expression.Constant(false), Expression.Constant(false)); 109 | } 110 | } 111 | } 112 | 113 | return Expression.Lambda>(exp, param); 114 | } 115 | } 116 | } 117 | -------------------------------------------------------------------------------- /DatatableJS.Data/DatatableExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Linq.Expressions; 5 | 6 | namespace DatatableJS.Data 7 | { 8 | /// 9 | /// Includes ToDataResult extension 10 | /// 11 | public static class DatatableExtensions 12 | { 13 | /// 14 | /// Executes IQueryable list and returns DataResult includes data 15 | /// 16 | /// 17 | /// 18 | /// 19 | /// DataResult 20 | public static DataResult ToDataResult(this IQueryable query, DataRequest request) where T : class 21 | { 22 | var result = new DataResult 23 | { 24 | draw = request.draw 25 | }; 26 | result.recordsTotal = result.recordsFiltered = query.Count(); 27 | 28 | foreach (var item in request.filters) 29 | { 30 | var exp = GetExpression(item.Operand, item.Field, item.Value); 31 | if (exp != null) 32 | { 33 | query = query.Where(exp); 34 | } 35 | } 36 | 37 | var listExp = new List(); 38 | 39 | if (!string.IsNullOrEmpty(request.search?.value)) 40 | { 41 | foreach (var item in request.columns.Where(a => a.searchable)) 42 | { 43 | ParameterExpression param = Expression.Parameter(typeof(T), "t"); 44 | MemberExpression member = Expression.Property(param, item.name); 45 | var operand = member.Type == typeof(string) ? Operand.Contains : Operand.Equal; 46 | listExp.Add(new FilterDef { Operand = operand, Field = item.name, Value = request.search.value, Operator = Operator.Or }); 47 | } 48 | } 49 | 50 | foreach (var item in request.columns.Where(a => a.searchable == true && !string.IsNullOrEmpty(a.search.value))) 51 | { 52 | ParameterExpression param = Expression.Parameter(typeof(T), "t"); 53 | MemberExpression member = Expression.Property(param, item.name); 54 | var operand = member.Type == typeof(string) ? Operand.Contains : Operand.Equal; 55 | listExp.Add(new FilterDef { Operand = operand, Field = item.name, Value = item.search.value, Operator = Operator.And }); 56 | } 57 | 58 | if (listExp.Any()) 59 | { 60 | Expression> exp = null; 61 | exp = ExpressionBuilder.GetExpression(listExp); 62 | if (exp != null) query = query.Where(exp); 63 | } 64 | 65 | if (listExp.Any() || request.filters.Any()) 66 | { 67 | result.recordsFiltered = query.Count(); 68 | } 69 | 70 | if (request.draw > 0) 71 | { 72 | if (!request.order.Any()) 73 | { 74 | query = query.OrderBy(request.columns[0].name ?? request.columns[1].name); 75 | } 76 | else 77 | { 78 | query = request.order[0].dir != "asc" 79 | ? query.OrderByDescending(request.columns[request.order[0].column].name) 80 | : query.OrderBy(request.columns[request.order[0].column].name); 81 | 82 | for (var i = 1; i < request.order.Count(); i++) 83 | { 84 | query = request.order[i].dir != "asc" 85 | ? query.ThenByDescending(request.columns[request.order[i].column].name) 86 | : query.ThenBy(request.columns[request.order[i].column].name); 87 | } 88 | } 89 | 90 | if (request.length != -1) 91 | { 92 | query = query.Skip(request.start).Take(request.length); 93 | } 94 | } 95 | 96 | result.data = query.ToList(); 97 | return result; 98 | } 99 | 100 | private static Expression> GetExpression(Operand operand, string field, string value) 101 | { 102 | return ExpressionBuilder 103 | .GetExpression(new FilterDef 104 | { 105 | Operand = operand, 106 | Field = field, 107 | Value = value, 108 | }); 109 | } 110 | 111 | private static IOrderedQueryable OrderBy( 112 | this IQueryable query, 113 | string memberName) 114 | { 115 | return query.OrderByCreate(memberName, nameof(OrderBy)); 116 | } 117 | 118 | private static IOrderedQueryable ThenBy( 119 | this IQueryable query, 120 | string memberName) 121 | { 122 | return query.OrderByCreate(memberName, nameof(ThenBy)); 123 | } 124 | 125 | private static IOrderedQueryable OrderByDescending( 126 | this IQueryable query, 127 | string memberName) 128 | { 129 | return query.OrderByCreate(memberName, nameof(OrderByDescending)); 130 | } 131 | 132 | private static IOrderedQueryable ThenByDescending( 133 | this IQueryable query, 134 | string memberName) 135 | { 136 | return query.OrderByCreate(memberName, nameof(ThenByDescending)); 137 | } 138 | 139 | private static IOrderedQueryable OrderByCreate(this IQueryable query, string memberName, string direction) 140 | { 141 | var typeParams = new ParameterExpression[] { Expression.Parameter(typeof(T), "") }; 142 | var pi = typeof(T).GetProperty(memberName); 143 | return (IOrderedQueryable)query.Provider.CreateQuery( 144 | Expression.Call( 145 | typeof(Queryable), 146 | direction, 147 | new Type[] { typeof(T), pi.PropertyType }, 148 | query.Expression, 149 | Expression.Lambda(Expression.Property(typeParams[0], pi), typeParams)) 150 | ); 151 | } 152 | } 153 | } 154 | -------------------------------------------------------------------------------- /DatatableJS.Data/DatatableJS.Data.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netstandard2.0 5 | Emrah KONDUR 6 | Emrah KONDUR 7 | true 8 | Executing IQueryable list objects server side in Entity Framework or any IQueryable list for Datatables request. 9 | https://github.com/ekondur/DatatableJS 10 | LICENSE.md 11 | https://www.datatablejs.net/ 12 | https://github.com/ekondur/DatatableJS 13 | git 14 | C#, Jquery Datatables, Entity Framework, Query, Linq 15 | Reverted Case Sensitive Issue 16 | en 17 | 3.8.0 18 | datatable-js.png 19 | 20 | true 21 | 22 | 23 | 24 | 25 | True 26 | 27 | 28 | 29 | True 30 | 31 | 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /DatatableJS.Data/Models/DataRequest.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace DatatableJS.Data 4 | { 5 | /// 6 | /// 7 | /// 8 | public class DataRequest 9 | { 10 | public int draw { get; set; } 11 | public int start { get; set; } 12 | public int length { get; set; } 13 | public List columns { get; set; } 14 | public List order { get; set; } 15 | public Search search { get; set; } 16 | public List filters { get; set; } 17 | 18 | public DataRequest() 19 | { 20 | filters = new List(); 21 | order = new List(); 22 | columns = new List(); 23 | } 24 | } 25 | 26 | public class Filter 27 | { 28 | public string Field { get; set; } 29 | public string Value { get; set; } 30 | public Operand Operand { get; set; } 31 | } 32 | 33 | public class Column 34 | { 35 | public string data { get; set; } 36 | public string name { get; set; } 37 | public bool searchable { get; set; } 38 | public bool orderable { get; set; } 39 | public Search search { get; set; } 40 | } 41 | 42 | public class Order 43 | { 44 | public int column { get; set; } 45 | public string dir { get; set; } 46 | } 47 | 48 | public class Search 49 | { 50 | public string value { get; set; } 51 | public bool regex { get; set; } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /DatatableJS.Data/Models/DataResult.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace DatatableJS.Data 4 | { 5 | public class DataResult where T : class 6 | { 7 | public int draw { get; set; } 8 | public long recordsTotal { get; set; } 9 | public long recordsFiltered { get; set; } 10 | public List data { get; set; } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /DatatableJS.Data/Models/FilterDef.cs: -------------------------------------------------------------------------------- 1 | namespace DatatableJS.Data 2 | { 3 | public class FilterDef 4 | { 5 | public string Field { get; set; } 6 | public string Value { get; set; } 7 | public Operand Operand { get; set; } 8 | public Operator Operator { get; set; } 9 | } 10 | 11 | public enum Operand 12 | { 13 | Equal, 14 | NotEqual, 15 | GreaterThan, 16 | LessThan, 17 | GreaterThanOrEqual, 18 | LessThanOrEqual, 19 | Contains, 20 | StartsWith, 21 | EndsWith 22 | } 23 | 24 | public enum Operator 25 | { 26 | And, 27 | Or 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /DatatableJS.Net/Builders/CallbackBuilder.cs: -------------------------------------------------------------------------------- 1 | namespace DatatableJS.Net 2 | { 3 | /// 4 | /// Generic callback builder class 5 | /// 6 | /// 7 | public class CallbackBuilder 8 | { 9 | private readonly GridBuilder _grid; 10 | 11 | /// 12 | /// Initializes a new instance of the class. 13 | /// 14 | /// 15 | public CallbackBuilder(GridBuilder grid) 16 | { 17 | _grid = grid; 18 | } 19 | 20 | /// 21 | /// Set createdRow function Reference: 22 | /// 23 | /// 24 | /// 25 | public CallbackBuilder CreatedRow(string functionName) 26 | { 27 | _grid._callBack.CreatedRow = functionName; 28 | return this; 29 | } 30 | 31 | /// 32 | /// Set drawCallback function Reference: 33 | /// 34 | /// 35 | /// 36 | public CallbackBuilder DrawCallback(string functionName) 37 | { 38 | _grid._callBack.DrawCallback = functionName; 39 | return this; 40 | } 41 | 42 | /// 43 | /// Set footerCallback function Reference: 44 | /// 45 | /// 46 | /// 47 | public CallbackBuilder FooterCallback(string functionName) 48 | { 49 | _grid._callBack.FooterCallback = functionName; 50 | return this; 51 | } 52 | 53 | /// 54 | /// Set formatNumber function Reference: 55 | /// 56 | /// 57 | /// 58 | public CallbackBuilder FormatNumber(string functionName) 59 | { 60 | _grid._callBack.FormatNumber = functionName; 61 | return this; 62 | } 63 | 64 | /// 65 | /// Set headerCallback function Reference: 66 | /// 67 | /// 68 | /// 69 | public CallbackBuilder HeaderCallback(string functionName) 70 | { 71 | _grid._callBack.HeaderCallback = functionName; 72 | return this; 73 | } 74 | 75 | /// 76 | /// Set infoCallback function Reference: 77 | /// 78 | /// 79 | /// 80 | public CallbackBuilder InfoCallback(string functionName) 81 | { 82 | _grid._callBack.InfoCallback = functionName; 83 | return this; 84 | } 85 | 86 | /// 87 | /// Set initComplete function Reference: 88 | /// 89 | /// 90 | /// 91 | public CallbackBuilder InitComplete(string functionName) 92 | { 93 | _grid._callBack.InitComplete = functionName; 94 | return this; 95 | } 96 | 97 | /// 98 | /// Set preDrawCallback function Reference: 99 | /// 100 | /// 101 | /// 102 | public CallbackBuilder PreDrawCallback(string functionName) 103 | { 104 | _grid._callBack.PreDrawCallback = functionName; 105 | return this; 106 | } 107 | 108 | /// 109 | /// Set rowCallback function Reference: 110 | /// 111 | /// 112 | /// 113 | public CallbackBuilder RowCallback(string functionName) 114 | { 115 | _grid._callBack.RowCallback = functionName; 116 | return this; 117 | } 118 | 119 | /// 120 | /// Set stateLoadCallback function Reference: 121 | /// 122 | /// 123 | /// 124 | public CallbackBuilder StateLoadCallback(string functionName) 125 | { 126 | _grid._callBack.StateLoadCallback = functionName; 127 | _grid._stateSave = true; 128 | return this; 129 | } 130 | 131 | /// 132 | /// Set stateLoadParams function Reference: 133 | /// 134 | /// 135 | /// 136 | public CallbackBuilder StateLoadParams(string functionName) 137 | { 138 | _grid._callBack.StateLoadParams = functionName; 139 | _grid._stateSave = true; 140 | return this; 141 | } 142 | 143 | /// 144 | /// Set stateLoaded function Reference: 145 | /// 146 | /// 147 | /// 148 | public CallbackBuilder StateLoaded(string functionName) 149 | { 150 | _grid._callBack.StateLoaded = functionName; 151 | _grid._stateSave = true; 152 | return this; 153 | } 154 | 155 | /// 156 | /// Set stateSaveCallback function Reference: 157 | /// 158 | /// 159 | /// 160 | public CallbackBuilder StateSaveCallback(string functionName) 161 | { 162 | _grid._callBack.StateSaveCallback = functionName; 163 | _grid._stateSave = true; 164 | return this; 165 | } 166 | 167 | /// 168 | /// Set stateSaveParams function Reference: 169 | /// 170 | /// 171 | /// 172 | public CallbackBuilder StateSaveParams(string functionName) 173 | { 174 | _grid._callBack.StateSaveParams = functionName; 175 | _grid._stateSave = true; 176 | return this; 177 | } 178 | } 179 | } 180 | -------------------------------------------------------------------------------- /DatatableJS.Net/Builders/ColReorderBuilder.cs: -------------------------------------------------------------------------------- 1 | namespace DatatableJS.Net 2 | { 3 | /// 4 | /// Generic col reorder builder class 5 | /// 6 | /// 7 | public class ColReorderBuilder 8 | { 9 | private readonly GridBuilder _grid; 10 | 11 | /// 12 | /// Initializes a new instance of the class. 13 | /// 14 | /// 15 | public ColReorderBuilder(GridBuilder grid) 16 | { 17 | _grid = grid; 18 | } 19 | 20 | /// 21 | /// Initial enablement state of ColReorder. Default value is "true". Reference: 22 | /// 23 | /// true 24 | /// 25 | public ColReorderBuilder Enable(bool value) 26 | { 27 | _grid._colReorder.Settings = true; 28 | _grid._colReorder.Enable = value; 29 | return this; 30 | } 31 | 32 | /// 33 | /// Disallow x columns from reordering (counting from the left). Default is "0". Reference: 34 | /// 35 | /// 0 36 | /// 37 | public ColReorderBuilder FixedColumnsLeft(int value) 38 | { 39 | _grid._colReorder.Settings = true; 40 | _grid._colReorder.FixedColumnsLeft = value; 41 | return this; 42 | } 43 | 44 | /// 45 | /// Disallow x columns from reordering (counting from the right). Default is "0". Reference: 46 | /// 47 | /// 0 48 | /// 49 | public ColReorderBuilder FixedColumnsRight(int value) 50 | { 51 | _grid._colReorder.Settings = true; 52 | _grid._colReorder.FixedColumnsRight = value; 53 | return this; 54 | } 55 | 56 | /// 57 | /// Set a default order for the columns in the table. Reference: 58 | /// 59 | /// 60 | /// 61 | public ColReorderBuilder Order(params int[] value) 62 | { 63 | _grid._colReorder.Settings = true; 64 | _grid._colReorder.Order = $"[{string.Join(",", value)}]"; 65 | return this; 66 | } 67 | 68 | /// 69 | /// Enable / disable live reordering of columns during a drag. Default is "true". Reference: 70 | /// 71 | /// 72 | /// 73 | public ColReorderBuilder RealTime(bool value) 74 | { 75 | _grid._colReorder.Settings = true; 76 | _grid._colReorder.RealTime = value; 77 | return this; 78 | } 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /DatatableJS.Net/Builders/ColumnBuilder.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel.DataAnnotations; 4 | using System.Linq; 5 | using System.Linq.Expressions; 6 | using System.Reflection; 7 | 8 | namespace DatatableJS.Net 9 | { 10 | /// 11 | /// Generic column builder class. 12 | /// 13 | /// 14 | public class ColumnBuilder 15 | { 16 | private readonly GridBuilder _grid; 17 | private ColumnDefinition _column { get; set; } 18 | 19 | /// 20 | /// Initializes a new instance of the class. 21 | /// 22 | /// The grid. 23 | public ColumnBuilder(GridBuilder grid) 24 | { 25 | _grid = grid; 26 | } 27 | 28 | /// 29 | /// Make a column with defined type properties. 30 | /// 31 | /// The type of the property. 32 | /// The property. 33 | /// 34 | public ColumnBuilder Field(Expression> property) 35 | { 36 | var member = property.Body as MemberExpression; 37 | _column = new ColumnDefinition 38 | { 39 | Data = ExpressionHelpers.PropertyName(property), 40 | Title = member.Member.GetCustomAttribute()?.Name ?? ExpressionHelpers.PropertyName(property), 41 | Render = member.Member.GetCustomAttribute() != null ? $@"moment(data).format('{member.Member.GetCustomAttribute().DataFormatString}')" : null, 42 | Type = ((PropertyInfo)member.Member).PropertyType 43 | }; 44 | _grid._columns.Add(_column); 45 | return this; 46 | } 47 | 48 | /// 49 | /// Set column title. 50 | /// 51 | /// 52 | /// 53 | public ColumnBuilder Title(string title) 54 | { 55 | _column.Title = title; 56 | return this; 57 | } 58 | 59 | /// 60 | /// Set column visible or hidden, default is true. 61 | /// 62 | /// 63 | /// 64 | public ColumnBuilder Visible(bool isVisible) 65 | { 66 | _column.Visible = isVisible; 67 | _column.Orderable = false; 68 | _column.Searchable = false; 69 | return this; 70 | } 71 | 72 | /// 73 | /// Set column orderable or not, default is true. 74 | /// 75 | /// 76 | /// 77 | public ColumnBuilder Orderable(bool isOrderable) 78 | { 79 | _column.Orderable = isOrderable; 80 | return this; 81 | } 82 | 83 | /// 84 | /// Set column searchable or not, default is true. 85 | /// 86 | /// 87 | /// 88 | public ColumnBuilder Searchable(bool isSearchable) 89 | { 90 | _column.Searchable = isSearchable; 91 | return this; 92 | } 93 | 94 | /// 95 | /// Set column width percentage. 96 | /// 97 | /// 98 | /// 99 | public ColumnBuilder Width(int width) 100 | { 101 | _column.Width = width; 102 | return this; 103 | } 104 | 105 | /// 106 | /// Set css class of column. 107 | /// 108 | /// 109 | /// 110 | public ColumnBuilder Class(string className) 111 | { 112 | _column.ClassName = className; 113 | return this; 114 | } 115 | 116 | /// 117 | /// Set default value for null data 118 | /// 119 | /// 120 | /// 121 | public ColumnBuilder DefaultContent(string defaultContent) 122 | { 123 | _column.DefaultContent = defaultContent; 124 | return this; 125 | } 126 | 127 | /// 128 | /// Set a jquery datatable date format. 129 | /// 130 | /// 131 | /// 132 | public ColumnBuilder Format(string format) 133 | { 134 | _column.Render = $@"moment(data).format('{format}')"; 135 | return this; 136 | } 137 | 138 | /// 139 | /// Customize column template using "data" for comparison. 140 | /// 141 | /// 142 | /// 143 | public ColumnBuilder Template(string template) 144 | { 145 | _column.Render = template; 146 | return this; 147 | } 148 | 149 | /// 150 | /// Define a link or button. 151 | /// 152 | /// 153 | /// 154 | /// 155 | /// 156 | /// 157 | /// 158 | /// 159 | public ColumnBuilder Command(Expression> property, string onClick, string iconClass, string btnClass, string text) 160 | { 161 | _column = new ColumnDefinition 162 | { 163 | Width = 1, 164 | Data = ExpressionHelpers.PropertyName(property), 165 | Orderable = false, 166 | Searchable = false, 167 | Render = $@"''+{(string.IsNullOrEmpty(text) ? (string.IsNullOrEmpty(iconClass) ? "data" : "''") : string.Format("' {0}'", text))}+''" 168 | }; 169 | _grid._columns.Add(_column); 170 | return this; 171 | } 172 | 173 | /// 174 | /// Define a link or button. 175 | /// 176 | /// 177 | /// 178 | /// 179 | /// 180 | /// 181 | /// 182 | public ColumnBuilder Command(Expression> property, string onClick, string iconClass, string btnClass) 183 | { 184 | return Command(property, onClick, iconClass, btnClass, ""); 185 | } 186 | 187 | /// 188 | /// Define a link or button. 189 | /// 190 | /// 191 | /// 192 | /// 193 | /// 194 | /// 195 | public ColumnBuilder Command(Expression> property, string onClick, string iconClass) 196 | { 197 | return Command(property, onClick, iconClass, "", ""); 198 | } 199 | 200 | /// 201 | /// Define a link or button. 202 | /// 203 | /// 204 | /// 205 | /// 206 | /// 207 | public ColumnBuilder Command(Expression> property, string onClick) 208 | { 209 | return Command(property, onClick, "", "", ""); 210 | } 211 | 212 | /// 213 | /// Add multiple command to define button group. 214 | /// 215 | /// 216 | /// 217 | /// 218 | /// 219 | /// 220 | /// 221 | /// 222 | public ColumnBuilder Commands(Expression> property, IEnumerable commands, string btnText, string btnClass, string iconClass) 223 | { 224 | _column = new ColumnDefinition 225 | { 226 | Width = 1, 227 | Data = ExpressionHelpers.PropertyName(property), 228 | Orderable = false, 229 | Searchable = false, 230 | }; 231 | _column.Render = $@"'
'+ 232 | ''+ 235 | '
    '+ 236 | {string.Join(Environment.NewLine, 237 | commands.Select(a => $@"'
  • {a.Title}
  • '+"))} 238 | '
'+ 239 | '
'"; 240 | _grid._columns.Add(_column); 241 | return this; 242 | } 243 | 244 | /// 245 | /// Add multiple command to define button group. 246 | /// 247 | /// 248 | /// 249 | /// 250 | /// 251 | public ColumnBuilder Commands(Expression> property, IEnumerable commands) 252 | { 253 | return Commands(property, commands, null, "btn-default", "caret"); 254 | } 255 | 256 | /// 257 | /// Add multiple command to define button group. 258 | /// 259 | /// 260 | /// 261 | /// 262 | /// 263 | /// 264 | public ColumnBuilder Commands(Expression> property, IEnumerable commands, string btnText) 265 | { 266 | return Commands(property, commands, btnText, "btn-default", "caret"); 267 | } 268 | 269 | /// 270 | /// Add multiple command to define button group. 271 | /// 272 | /// 273 | /// 274 | /// 275 | /// 276 | /// 277 | /// 278 | public ColumnBuilder Commands(Expression> property, IEnumerable commands, string btnText, string btnClass) 279 | { 280 | return Commands(property, commands, btnText, btnClass, "caret"); 281 | } 282 | } 283 | } 284 | -------------------------------------------------------------------------------- /DatatableJS.Net/Builders/FilterBuilder.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq.Expressions; 3 | 4 | namespace DatatableJS.Net 5 | { 6 | /// 7 | /// Generic filter builder class. 8 | /// 9 | /// 10 | public class FilterBuilder 11 | { 12 | private readonly GridBuilder _grid; 13 | private FilterDefinition _filter { get; set; } 14 | 15 | /// 16 | /// Initializes a new instance of the class. 17 | /// 18 | /// The grid. 19 | public FilterBuilder(GridBuilder grid) 20 | { 21 | _grid = grid; 22 | } 23 | 24 | /// 25 | /// Adds the specified property for filter. 26 | /// 27 | /// The type of the property. 28 | /// The property. 29 | /// 30 | public FilterBuilder Add(Expression> property) 31 | { 32 | _filter = new FilterDefinition 33 | { 34 | Field = ExpressionHelpers.PropertyName(property), 35 | }; 36 | return this; 37 | } 38 | 39 | /// 40 | /// Equals the specified value. 41 | /// 42 | /// The value. 43 | /// 44 | public FilterBuilder Equal(object value) 45 | { 46 | _filter.Operand = Operand.Equal; 47 | _filter.Value = value.ToString(); 48 | _grid._filters.Add(_filter); 49 | return this; 50 | } 51 | 52 | /// 53 | /// Nots the equal. 54 | /// 55 | /// The value. 56 | /// 57 | public FilterBuilder NotEqual(object value) 58 | { 59 | _filter.Operand = Operand.NotEqual; 60 | _filter.Value = value.ToString(); 61 | _grid._filters.Add(_filter); 62 | return this; 63 | } 64 | 65 | /// 66 | /// Greaters the than. 67 | /// 68 | /// The value. 69 | /// 70 | public FilterBuilder GreaterThan(object value) 71 | { 72 | _filter.Operand = Operand.GreaterThan; 73 | _filter.Value = value.ToString(); 74 | _grid._filters.Add(_filter); 75 | return this; 76 | } 77 | 78 | /// 79 | /// Determines whether this instance contains the object. 80 | /// 81 | /// The value. 82 | /// 83 | public FilterBuilder Contains(object value) 84 | { 85 | _filter.Operand = Operand.Contains; 86 | _filter.Value = value.ToString(); 87 | _grid._filters.Add(_filter); 88 | return this; 89 | } 90 | 91 | /// 92 | /// Endses the with. 93 | /// 94 | /// The value. 95 | /// 96 | public FilterBuilder EndsWith(object value) 97 | { 98 | _filter.Operand = Operand.EndsWith; 99 | _filter.Value = value.ToString(); 100 | _grid._filters.Add(_filter); 101 | return this; 102 | } 103 | 104 | /// 105 | /// Greaters the than or equal. 106 | /// 107 | /// The value. 108 | /// 109 | public FilterBuilder GreaterThanOrEqual(object value) 110 | { 111 | _filter.Operand = Operand.GreaterThanOrEqual; 112 | _filter.Value = value.ToString(); 113 | _grid._filters.Add(_filter); 114 | return this; 115 | } 116 | 117 | /// 118 | /// Lesses the than. 119 | /// 120 | /// The value. 121 | /// 122 | public FilterBuilder LessThan(object value) 123 | { 124 | _filter.Operand = Operand.LessThan; 125 | _filter.Value = value.ToString(); 126 | _grid._filters.Add(_filter); 127 | return this; 128 | } 129 | 130 | /// 131 | /// Lesses the than or equal. 132 | /// 133 | /// The value. 134 | /// 135 | public FilterBuilder LessThanOrEqual(object value) 136 | { 137 | _filter.Operand = Operand.LessThanOrEqual; 138 | _filter.Value = value.ToString(); 139 | _grid._filters.Add(_filter); 140 | return this; 141 | } 142 | 143 | /// 144 | /// Startses the with. 145 | /// 146 | /// The value. 147 | /// 148 | public FilterBuilder StartsWith(object value) 149 | { 150 | _filter.Operand = Operand.StartsWith; 151 | _filter.Value = value.ToString(); 152 | _grid._filters.Add(_filter); 153 | return this; 154 | } 155 | } 156 | } 157 | -------------------------------------------------------------------------------- /DatatableJS.Net/Builders/GridBuilder.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | 5 | namespace DatatableJS.Net 6 | { 7 | /// 8 | /// Generic grid builder class. 9 | /// 10 | /// 11 | public class GridBuilder 12 | { 13 | internal string _name { get; private set; } = "DataGrid"; 14 | internal string _url { get; private set; } 15 | internal bool _ordering { get; private set; } = true; 16 | internal bool _searching { get; private set; } = true; 17 | internal int _leftColumns { get; private set; } 18 | internal int _rightColumns { get; private set; } 19 | internal bool _serverSide { get; private set; } 20 | internal string _method { get; private set; } 21 | internal bool _camelCase { get; private set; } 22 | internal string _data { get; private set; } 23 | internal string _cssClass { get; private set; } = "display nowrap dataTable dtr-inline collapsed"; 24 | internal string _captionTop { get; private set; } 25 | internal string _captionBottom { get; private set; } 26 | internal bool _paging { get; private set; } = true; 27 | internal bool _columnSearching { get; private set; } 28 | internal string _columnSearchingCss { get; private set; } 29 | internal SearchPosition _columnSearchPosition { get; set; } = SearchPosition.Footer; 30 | internal List _lengthMenuValues { get; private set; } = new List(); 31 | internal List _lengthMenuDisplayedTexts { get; private set; } = new List(); 32 | internal int? _pageLength { get; private set; } 33 | internal bool _processing { get; private set; } = true; 34 | internal bool _scrollX { get; private set; } 35 | internal bool _stateSave { get; set; } 36 | internal string _dom { get; set; } 37 | 38 | internal bool _selectEnable { get; private set; } 39 | internal SelectStyle _selectStyle { get; private set; } 40 | internal SelectItems _selectItems { get; private set; } 41 | internal bool _selectInfo { get; private set; } 42 | internal bool _selectToggleable { get; private set; } 43 | 44 | internal List _columns = new List(); 45 | internal List _filters = new List(); 46 | internal List _orders = new List(); 47 | 48 | internal CallbackModel _callBack = new CallbackModel(); 49 | internal LanguageModel _language = new LanguageModel(); 50 | internal ColReorderModel _colReorder = new ColReorderModel(); 51 | 52 | /// 53 | /// Default name is "DataGrid". 54 | /// 55 | /// 56 | /// 57 | public GridBuilder Name(string name) 58 | { 59 | _name = name; 60 | return this; 61 | } 62 | 63 | /// 64 | /// Define table columns. 65 | /// 66 | /// 67 | /// 68 | public GridBuilder Columns(Action> config) 69 | { 70 | var builder = new ColumnBuilder(this); 71 | config(builder); 72 | return this; 73 | } 74 | 75 | /// 76 | /// Filter data with request. 77 | /// 78 | /// 79 | /// 80 | public GridBuilder Filters(Action> config) 81 | { 82 | var builder = new FilterBuilder(this); 83 | config(builder); 84 | return this; 85 | } 86 | 87 | /// 88 | /// Enable ordering and set default orders. 89 | /// 90 | /// 91 | /// 92 | public GridBuilder Orders(Action> config) 93 | { 94 | _ordering = true; 95 | var builder = new OrderBuilder(this); 96 | config(builder); 97 | return this; 98 | } 99 | 100 | /// 101 | /// Set callback functions. Reference: 102 | /// 103 | /// 104 | /// 105 | public GridBuilder Callbacks(Action> config) 106 | { 107 | var builder = new CallbackBuilder(this); 108 | config(builder); 109 | return this; 110 | } 111 | 112 | /// 113 | /// Set the action url, type and json naming policy is camelcase, default is false. 114 | /// 115 | /// 116 | /// 117 | /// 118 | /// 119 | public GridBuilder URL(string url, string method, bool camelCase) 120 | { 121 | _url = url; 122 | _method = method; 123 | _camelCase = camelCase; 124 | return this; 125 | } 126 | 127 | /// 128 | /// Set the action url and type. 129 | /// 130 | /// 131 | /// 132 | /// 133 | public GridBuilder URL(string url, string method) 134 | { 135 | return URL(url, method, false); 136 | } 137 | 138 | /// 139 | /// Set the action url and type, default type is GET. 140 | /// 141 | /// 142 | /// 143 | public GridBuilder URL(string url) 144 | { 145 | return URL(url, "GET", false); 146 | } 147 | 148 | /// 149 | /// Disable or enable ordering, default is true. 150 | /// 151 | /// 152 | /// 153 | public GridBuilder Ordering(bool ordering) 154 | { 155 | _ordering = ordering; 156 | return this; 157 | } 158 | 159 | /// 160 | /// Disable or enable searching, default is true. 161 | /// 162 | /// 163 | /// 164 | public GridBuilder Searching(bool searching) 165 | { 166 | _searching = searching; 167 | return this; 168 | } 169 | 170 | /// 171 | /// Fix the table columns from left or right. 172 | /// 173 | /// 174 | /// 175 | /// 176 | public GridBuilder FixedColumns(int leftColumns, int rightColumns) 177 | { 178 | _leftColumns = leftColumns; 179 | _rightColumns = rightColumns; 180 | return this; 181 | } 182 | 183 | /// 184 | /// Fix the table columns from left. 185 | /// 186 | /// 187 | /// 188 | public GridBuilder FixedColumns(int leftColumns) 189 | { 190 | return FixedColumns(leftColumns, 0); 191 | } 192 | 193 | /// 194 | /// Enable server-side processing mode. 195 | /// 196 | /// 197 | /// 198 | public GridBuilder ServerSide(bool serverSide) 199 | { 200 | _serverSide = _paging ? serverSide : _paging; 201 | return this; 202 | } 203 | 204 | /// 205 | /// Passing additional data to action set name of javascript function. 206 | /// 207 | /// 208 | /// 209 | public GridBuilder Data(string data) 210 | { 211 | _data = data; 212 | return this; 213 | } 214 | 215 | /// 216 | /// Set css class of table. 217 | /// 218 | /// 219 | /// 220 | public GridBuilder Class(string cssClass) 221 | { 222 | _cssClass = cssClass; 223 | return this; 224 | } 225 | 226 | /// 227 | /// Define table top or bottom captions. 228 | /// 229 | /// 230 | /// 231 | /// 232 | public GridBuilder Captions(string top, string bottom) 233 | { 234 | _captionTop = top; 235 | _captionBottom = bottom; 236 | return this; 237 | } 238 | 239 | /// 240 | /// Define table top caption. 241 | /// 242 | /// 243 | /// 244 | public GridBuilder Captions(string top) 245 | { 246 | return Captions(top, null); 247 | } 248 | 249 | /// 250 | /// Disable or enable paging, default is true. 251 | /// 252 | /// 253 | /// 254 | public GridBuilder Paging(bool paging) 255 | { 256 | if (!paging) 257 | { 258 | _serverSide = false; 259 | } 260 | _paging = paging; 261 | return this; 262 | } 263 | 264 | /// 265 | /// Specify language json url from cdn or local. 266 | /// 267 | /// 268 | /// 269 | public GridBuilder Language(string url) 270 | { 271 | _language.URL = url; 272 | return this; 273 | } 274 | 275 | /// 276 | /// Enable columns search feature. 277 | /// 278 | /// if set to true [searching]. 279 | /// 280 | /// default is footer 281 | /// 282 | public GridBuilder ColumnSearching(bool searching, string css, SearchPosition position) 283 | { 284 | _columnSearching = searching; 285 | _columnSearchingCss = css; 286 | _columnSearchPosition = position; 287 | return this; 288 | } 289 | 290 | /// 291 | /// Enable columns search feature. 292 | /// 293 | /// if set to true [searching]. 294 | /// default is footer 295 | /// 296 | public GridBuilder ColumnSearching(bool searching, SearchPosition position) 297 | { 298 | return ColumnSearching(searching, "", position); 299 | } 300 | 301 | /// 302 | /// Enable columns search feature. 303 | /// 304 | /// if set to true [searching]. 305 | /// 306 | /// 307 | public GridBuilder ColumnSearching(bool searching, string css) 308 | { 309 | return ColumnSearching(searching, css, SearchPosition.Footer); 310 | } 311 | 312 | /// 313 | /// Enable columns search feature. 314 | /// 315 | /// 316 | /// 317 | public GridBuilder ColumnSearching(bool searching) 318 | { 319 | return ColumnSearching(searching, "", SearchPosition.Footer); 320 | } 321 | 322 | /// 323 | /// Define table length menu. 324 | /// 325 | /// 326 | /// 327 | /// 328 | /// 329 | public GridBuilder LengthMenu(int[] values, bool hasAll, string allText) 330 | { 331 | _lengthMenuValues = values.ToList(); 332 | _lengthMenuDisplayedTexts = values.Select(x => x.ToString()).ToList(); 333 | 334 | if (!_pageLength.HasValue) 335 | { 336 | _pageLength = _lengthMenuValues.FirstOrDefault(); 337 | } 338 | 339 | if (hasAll) 340 | { 341 | _lengthMenuValues.Add(-1); 342 | _lengthMenuDisplayedTexts.Add(allText); 343 | } 344 | 345 | return this; 346 | } 347 | 348 | /// 349 | /// Define table length menu. 350 | /// 351 | /// 352 | /// 353 | /// 354 | public GridBuilder LengthMenu(int[] values, bool hasAll) 355 | { 356 | return LengthMenu(values, hasAll, "All"); 357 | } 358 | 359 | /// 360 | /// Define table length menu. 361 | /// 362 | /// 363 | /// 364 | public GridBuilder LengthMenu(int[] values) 365 | { 366 | return LengthMenu(values, false, "All"); 367 | } 368 | 369 | /// 370 | /// Define table page length. 371 | /// 372 | /// 373 | /// 374 | public GridBuilder PageLength(int value) 375 | { 376 | _pageLength = value; 377 | 378 | if (!_lengthMenuValues.Any()) 379 | { 380 | _lengthMenuValues = new List { value, value * 2, value * 3, value * 4, value * 5 }; 381 | _lengthMenuDisplayedTexts = _lengthMenuValues.Select(x => x.ToString()).ToList(); 382 | } 383 | return this; 384 | } 385 | 386 | /// 387 | /// Enable or disable the display of a 'processing' indicator when the table is being processed, Default is true. 388 | /// 389 | /// 390 | /// 391 | public GridBuilder Processing(bool processing) 392 | { 393 | _processing = processing; 394 | return this; 395 | } 396 | 397 | /// 398 | /// Enable horizontal scrolling. When a table is too wide to fit into a certain layout, or you have a large number of columns in the table, you can enable horizontal (x) scrolling to show the table in a viewport, which can be scrolled. 399 | /// 400 | /// 401 | /// 402 | public GridBuilder ScrollX(bool scrollX) 403 | { 404 | _scrollX = scrollX; 405 | return this; 406 | } 407 | 408 | /// 409 | /// Enable or disable state saving such as pagination position, display length, filtering and sorting information. 410 | /// 411 | /// 412 | /// 413 | public GridBuilder StateSave(bool stateSave) 414 | { 415 | _stateSave = stateSave; 416 | return this; 417 | } 418 | 419 | /// 420 | /// Enable selection and set properties 421 | /// 422 | /// Enable the selectable grid, default is false. 423 | /// Set the selection behaviour. 424 | /// Set the selection style. 425 | /// Disable the visibility of selected row info on grid, default is true. 426 | /// Disable the toggleable selection, default is true. 427 | /// 428 | public GridBuilder Selecting(bool enable, SelectItems items, SelectStyle style, bool info, bool toggleable) 429 | { 430 | _selectEnable = enable; 431 | _selectItems = items; 432 | _selectStyle = style; 433 | _selectInfo = info; 434 | _selectToggleable = toggleable; 435 | 436 | if (items == SelectItems.Checkbox) 437 | { 438 | var column = new ColumnDefinition 439 | { 440 | ClassName = "select-checkbox", 441 | Orderable = false, 442 | Searchable = false, 443 | Width = 5, 444 | Render = null 445 | }; 446 | _columns.Insert(0, column); 447 | } 448 | 449 | return this; 450 | } 451 | 452 | /// 453 | /// Enable selection and set properties 454 | /// 455 | /// 456 | /// 457 | /// 458 | /// 459 | /// 460 | public GridBuilder Selecting(bool enable, SelectItems items, SelectStyle style, bool info) 461 | { 462 | return Selecting(enable, items, style, info, true); 463 | } 464 | 465 | /// 466 | /// Enable selection and set properties 467 | /// 468 | /// 469 | /// 470 | /// 471 | /// 472 | public GridBuilder Selecting(bool enable, SelectItems items, SelectStyle style) 473 | { 474 | return Selecting(enable, items, style, true, true); 475 | } 476 | 477 | /// 478 | /// Enable selection and set properties 479 | /// 480 | /// 481 | /// 482 | /// 483 | public GridBuilder Selecting(bool enable, SelectItems items) 484 | { 485 | return Selecting(enable, items, SelectStyle.Default, true, true); 486 | } 487 | 488 | /// 489 | /// Enable selection and set properties 490 | /// 491 | /// 492 | /// 493 | public GridBuilder Selecting(bool enable) 494 | { 495 | return Selecting(enable, SelectItems.Row, SelectStyle.Default, true, true); 496 | } 497 | 498 | /// 499 | /// Enable ColReorder for a table. Reference: 500 | /// 501 | /// 502 | public GridBuilder ColReorder(bool value) 503 | { 504 | _colReorder.ColReorder = value; 505 | return this; 506 | } 507 | 508 | /// 509 | /// Enable and configure the ColReorder extension for DataTables. Reference: 510 | /// 511 | /// 512 | /// 513 | public GridBuilder ColReorder(Action> config) 514 | { 515 | var builder = new ColReorderBuilder(this); 516 | config(builder); 517 | return this; 518 | } 519 | } 520 | } 521 | -------------------------------------------------------------------------------- /DatatableJS.Net/Builders/LanguageBuilder.cs: -------------------------------------------------------------------------------- 1 | namespace DatatableJS.Net 2 | { 3 | /// 4 | /// Generic language builder class 5 | /// 6 | /// 7 | public class LanguageBuilder 8 | { 9 | private readonly GridBuilder _grid; 10 | 11 | /// 12 | /// Initializes a new instance of the class. 13 | /// 14 | /// 15 | public LanguageBuilder(GridBuilder grid) 16 | { 17 | _grid = grid; 18 | } 19 | 20 | /// 21 | /// Set the decimal place character. Reference: 22 | /// 23 | /// 24 | /// 25 | public LanguageBuilder Decimal(string place) 26 | { 27 | _grid._language.Decimal = place; 28 | return this; 29 | } 30 | 31 | /// 32 | /// This string is shown when the table is empty of data (regardless of filtering). Reference: 33 | /// 34 | /// No data available in table 35 | /// 36 | public LanguageBuilder EmptyTable(string message) 37 | { 38 | _grid._language.EmptyTable = message; 39 | return this; 40 | } 41 | 42 | /// 43 | /// This string gives information to the end user about the information that is current on display on the page. Reference: 44 | /// 45 | /// Showing _START_ to _END_ of _TOTAL_ entries 46 | /// 47 | public LanguageBuilder Info(string message) 48 | { 49 | _grid._language.Info = message; 50 | return this; 51 | } 52 | 53 | /// 54 | /// Display information string for when the table is empty. Reference: 55 | /// 56 | /// Showing 0 to 0 of 0 entries 57 | /// 58 | public LanguageBuilder InfoEmpty(string message) 59 | { 60 | _grid._language.InfoEmpty = message; 61 | return this; 62 | } 63 | 64 | /// 65 | /// When a user filters the information in a table, this string is appended to the information (info) to give an idea of how strong the filtering is. Reference: 66 | /// 67 | /// (filtered from _MAX_ total entries) 68 | /// 69 | public LanguageBuilder InfoFiltered(string message) 70 | { 71 | _grid._language.InfoFiltered = message; 72 | return this; 73 | } 74 | 75 | /// 76 | /// If can be useful to append extra information to the info string at times, and this variable does exactly that. Reference: 77 | /// 78 | /// 79 | /// 80 | public LanguageBuilder InfoPostFix(string message) 81 | { 82 | _grid._language.InfoPostFix = message; 83 | return this; 84 | } 85 | 86 | /// 87 | /// The thousands separator option is used for output of information only. Reference: 88 | /// 89 | /// , 90 | /// 91 | public LanguageBuilder Thousands(string place) 92 | { 93 | _grid._language.Thousands = place; 94 | return this; 95 | } 96 | 97 | /// 98 | /// Detail the action that will be taken when the drop down menu for the pagination length option is changed. Reference: 99 | /// 100 | /// Show _MENU_ entries 101 | /// 102 | public LanguageBuilder LengthMenu(string message) 103 | { 104 | _grid._language.LengthMenu = message; 105 | return this; 106 | } 107 | 108 | /// 109 | /// This message is shown in an empty row in the table to indicate to the end user the the data is being loaded. Reference: 110 | /// 111 | /// Loading... 112 | /// 113 | public LanguageBuilder LoadingRecords(string message) 114 | { 115 | _grid._language.LoadingRecords = message; 116 | return this; 117 | } 118 | 119 | /// 120 | /// Text that is displayed when the table is processing a user action (usually a sort command or similar). Reference: 121 | /// 122 | /// {Empty string} 123 | /// 124 | public LanguageBuilder Processing(string message) 125 | { 126 | _grid._language.Processing = message; 127 | return this; 128 | } 129 | 130 | /// 131 | /// Sets the string that is used for DataTables filtering input control. Reference: 132 | /// 133 | /// Search: 134 | /// 135 | public LanguageBuilder Search(string message) 136 | { 137 | _grid._language.Search = message; 138 | return this; 139 | } 140 | 141 | /// 142 | /// Text shown inside the table records when the is no information to be displayed after filtering. Reference: 143 | /// 144 | /// No matching records found 145 | /// 146 | public LanguageBuilder ZeroRecords(string message) 147 | { 148 | _grid._language.ZeroRecords = message; 149 | return this; 150 | } 151 | 152 | /// 153 | /// Pagination string used by DataTables for the built-in pagination control types. Reference: 154 | /// 155 | /// First 156 | /// Last 157 | /// Next 158 | /// Previous 159 | /// 160 | public LanguageBuilder Paginate(string first, string last, string next, string previous) 161 | { 162 | _grid._language.Paginate.First = first; 163 | _grid._language.Paginate.Last = last; 164 | _grid._language.Paginate.Next = next; 165 | _grid._language.Paginate.Previous = previous; 166 | return this; 167 | } 168 | 169 | /// 170 | /// Language strings used for WAI-ARIA specific attributes. Reference: 171 | /// 172 | /// : activate to sort column ascending 173 | /// : activate to sort column descending 174 | /// 175 | public LanguageBuilder Aria(string sortAscending, string sortDescending) 176 | { 177 | _grid._language.Aria.SortAscending = sortAscending; 178 | _grid._language.Aria.SortDescending = sortDescending; 179 | return this; 180 | } 181 | } 182 | } 183 | -------------------------------------------------------------------------------- /DatatableJS.Net/Builders/OrderBuilder.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | using System.Linq.Expressions; 4 | using DatatableJS.Net.Exceptions; 5 | 6 | namespace DatatableJS.Net 7 | { 8 | /// 9 | /// Generic order builder class. 10 | /// 11 | /// 12 | public class OrderBuilder 13 | { 14 | private readonly GridBuilder _grid; 15 | private OrderDefinition _order { get; set; } 16 | 17 | /// 18 | /// Initializes a new instance of the class. 19 | /// 20 | /// The grid. 21 | public OrderBuilder(GridBuilder grid) 22 | { 23 | _grid = grid; 24 | } 25 | 26 | /// 27 | /// Adds the specified property for default ordering. 28 | /// 29 | /// The type of the property. 30 | /// The property. 31 | /// The order. 32 | /// 33 | public OrderBuilder Add(Expression> property, OrderBy orderBy) 34 | { 35 | var propertyName = ExpressionHelpers.PropertyName(property); 36 | 37 | var column = _grid._columns 38 | .Where(c => c.Data != null && c.Data.Equals(propertyName)) 39 | .FirstOrDefault(); 40 | 41 | if (column == null) 42 | { 43 | throw new ColumnNotFoundException(string.Format("Column not found for property {0}", propertyName)); 44 | } 45 | 46 | var columnIndex = _grid._columns.IndexOf(column); 47 | 48 | _order = new OrderDefinition 49 | { 50 | Field = propertyName, 51 | Column = columnIndex, 52 | OrderBy = orderBy 53 | }; 54 | _grid._orders.Add(_order); 55 | 56 | return this; 57 | } 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /DatatableJS.Net/DatatableJS.Net.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net45;net451;net452;net46;net461;net462;net47;net471;net472;net48 5 | DatatableJS is a helper to create a grid with Jquery Datatables and provides a request to retrive data generically from a repo. It possible to use many Jquery Datatables features with Html Helper. It gives serverside or client side options. 6 | Emrah KONDUR 7 | true 8 | https://github.com/ekondur/DatatableJS 9 | https://www.datatablejs.net/ 10 | README.md 11 | https://github.com/ekondur/DatatableJS 12 | git 13 | LICENSE.md 14 | C#, Helper, Jquery Datatables, Entity Framework, Mvc 15 | Fixed NRE issue during ordering 16 | 3.9.1 17 | 3.9.1 18 | 3.9.1 19 | datatable-js.png 20 | 21 | true 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | True 37 | 38 | 39 | 40 | True 41 | 42 | 43 | 44 | True 45 | 46 | 47 | 48 | 49 | 50 | -------------------------------------------------------------------------------- /DatatableJS.Net/Definitions/ColumnDefinition.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace DatatableJS.Net 4 | { 5 | #pragma warning disable CS1591 // Missing XML comment for publicly visible type or member 6 | public class ColumnDefinition 7 | { 8 | public string Data { get; set; } 9 | public string Title { get; set; } 10 | public bool Visible { get; set; } = true; 11 | public bool Searchable { get; set; } = true; 12 | public bool Orderable { get; set; } = true; 13 | public int Width { get; set; } 14 | public string ClassName { get; set; } = ""; 15 | public string Render { get; set; } = "data"; 16 | public Type Type { get; set; } 17 | public string DefaultContent { get; set; } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /DatatableJS.Net/Definitions/FilterDefinition.cs: -------------------------------------------------------------------------------- 1 | namespace DatatableJS.Net 2 | { 3 | #pragma warning disable CS1591 // Missing XML comment for publicly visible type or member 4 | public class FilterDefinition 5 | { 6 | public string Field { get; set; } 7 | public string Value { get; set; } 8 | public Operand Operand { get; set; } 9 | } 10 | 11 | public enum Operand 12 | { 13 | Equal, 14 | NotEqual, 15 | GreaterThan, 16 | LessThan, 17 | GreaterThanOrEqual, 18 | LessThanOrEqual, 19 | Contains, 20 | StartsWith, 21 | EndsWith 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /DatatableJS.Net/Definitions/OrderDefinition.cs: -------------------------------------------------------------------------------- 1 | namespace DatatableJS.Net 2 | { 3 | #pragma warning disable CS1591 // Missing XML comment for publicly visible type or member 4 | public class OrderDefinition 5 | { 6 | public string Field { get; set; } 7 | public int Column { get; set; } 8 | public OrderBy OrderBy { get; set; } 9 | } 10 | 11 | public enum OrderBy 12 | { 13 | Ascending, 14 | Descending 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /DatatableJS.Net/Exceptions/ColumnNotFoundException.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace DatatableJS.Net.Exceptions 4 | { 5 | /// 6 | /// Exception thrown when a column is not found. 7 | /// 8 | public class ColumnNotFoundException : Exception 9 | { 10 | /// 11 | /// Create a new exception of type ColumnNotFoundException. 12 | /// 13 | public ColumnNotFoundException() 14 | { 15 | } 16 | 17 | /// 18 | /// Create a new exception of type ColumnNotFoundException. 19 | /// 20 | /// 21 | public ColumnNotFoundException(string message) 22 | : base(message) 23 | { 24 | } 25 | 26 | /// 27 | /// Create a new exception of type ColumnNotFoundException. 28 | /// 29 | /// 30 | /// 31 | public ColumnNotFoundException(string message, Exception inner) 32 | : base(message, inner) 33 | { 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /DatatableJS.Net/Models/CallbackModel.cs: -------------------------------------------------------------------------------- 1 | namespace DatatableJS.Net 2 | { 3 | public class CallbackModel 4 | { 5 | public string CreatedRow { get; set; } 6 | public string DrawCallback { get; set; } 7 | public string FooterCallback { get; set; } 8 | public string FormatNumber { get; set; } 9 | public string HeaderCallback { get; set; } 10 | public string InfoCallback { get; set; } 11 | public string InitComplete { get; set; } 12 | public string PreDrawCallback { get; set; } 13 | public string RowCallback { get; set; } 14 | public string StateLoadCallback { get; set; } 15 | public string StateLoadParams { get; set; } 16 | public string StateLoaded { get; set; } 17 | public string StateSaveCallback { get; set; } 18 | public string StateSaveParams { get; set; } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /DatatableJS.Net/Models/ColReorderModel.cs: -------------------------------------------------------------------------------- 1 | namespace DatatableJS.Net 2 | { 3 | class ColReorderModel 4 | { 5 | public bool ColReorder { get; set; } 6 | public bool Settings { get; set; } 7 | public bool Enable { get; set; } = true; 8 | public int FixedColumnsLeft { get; set; } 9 | public int FixedColumnsRight { get; set; } 10 | public string Order { get; set; } = "null"; 11 | public bool RealTime { get; set; } = true; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /DatatableJS.Net/Models/Command.cs: -------------------------------------------------------------------------------- 1 | namespace DatatableJS.Net 2 | { 3 | /// 4 | /// Define a command. 5 | /// 6 | public class Command 7 | { 8 | /// 9 | /// Gets the title. 10 | /// 11 | /// 12 | /// The title. 13 | /// 14 | public string Title { get; private set; } 15 | /// 16 | /// Gets the on click. 17 | /// 18 | /// 19 | /// The on click. 20 | /// 21 | public string OnClick { get; private set; } 22 | /// 23 | /// Initializes a new instance of the class. 24 | /// 25 | /// The title. 26 | /// The on click. 27 | public Command(string title, string onClick) 28 | { 29 | Title = title; 30 | OnClick = onClick; 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /DatatableJS.Net/Models/Enums.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel; 2 | 3 | namespace DatatableJS.Net 4 | { 5 | /// 6 | /// Set which items are selectable (row, column, cell, row with checkbox). Default is row. 7 | /// 8 | public enum SelectItems 9 | { 10 | /// 11 | /// Enable row selection. 12 | /// 13 | [Description("row")] 14 | Row, 15 | 16 | /// 17 | /// Enable column selection. 18 | /// 19 | [Description("column")] 20 | Column, 21 | 22 | /// 23 | /// Enable cell selection. 24 | /// 25 | [Description("cell")] 26 | Cell, 27 | 28 | /// 29 | /// Enable row selection with checkbox. 30 | /// 31 | [Description("row")] 32 | Checkbox 33 | } 34 | 35 | /// 36 | /// Set select style functionalities. 37 | /// 38 | public enum SelectStyle 39 | { 40 | /// 41 | /// Select just for single item, to select multiple just click with CTRL button. 42 | /// 43 | [Description("os")] 44 | Default, 45 | 46 | /// 47 | /// Only single item can be selected. 48 | /// 49 | [Description("single")] 50 | Single, 51 | 52 | /// 53 | /// Multiple selectable with one click 54 | /// 55 | [Description("multi")] 56 | Multi, 57 | 58 | /// 59 | /// Multi-item with rangle selection 60 | /// 61 | [Description("multi+shift")] 62 | MultiShift 63 | } 64 | 65 | /// 66 | /// Select position of the column search box 67 | /// 68 | public enum SearchPosition 69 | { 70 | /// 71 | /// Footer 72 | /// 73 | Footer, 74 | 75 | /// 76 | /// Header 77 | /// 78 | Header 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /DatatableJS.Net/Models/LanguageModel.cs: -------------------------------------------------------------------------------- 1 | namespace DatatableJS.Net 2 | { 3 | internal class LanguageModel 4 | { 5 | internal string URL { get; set; } 6 | internal string Decimal { get; set; } 7 | internal string EmptyTable { get; set; } 8 | internal string Info { get; set; } 9 | internal string InfoEmpty { get; set; } 10 | internal string InfoFiltered { get; set; } 11 | internal string InfoPostFix { get; set; } 12 | internal string Thousands { get; set; } 13 | internal string LengthMenu { get; set; } 14 | internal string LoadingRecords { get; set; } 15 | internal string Processing { get; set; } 16 | internal string Search { get; set; } 17 | internal string ZeroRecords { get; set; } 18 | internal PaginateModel Paginate { get; set; } = new PaginateModel(); 19 | internal AriaModel Aria { get; set; } = new AriaModel(); 20 | } 21 | 22 | internal class PaginateModel 23 | { 24 | public string First { get; set; } 25 | public string Last { get; set; } 26 | public string Next { get; set; } 27 | public string Previous { get; set; } 28 | } 29 | 30 | internal class AriaModel 31 | { 32 | public string SortAscending { get; set; } 33 | public string SortDescending { get; set; } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /DatatableJS.Net/Utilities/ExpressionHelpers.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq.Expressions; 3 | 4 | namespace DatatableJS.Net 5 | { 6 | internal static class ExpressionHelpers 7 | { 8 | public static string PropertyName(Expression> expression) 9 | { 10 | var body = expression.Body as MemberExpression; 11 | 12 | if (body == null) 13 | { 14 | body = ((UnaryExpression)expression.Body).Operand as MemberExpression; 15 | } 16 | 17 | return body.Member.Name; 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /DatatableJS.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 16 4 | VisualStudioVersion = 16.0.31410.357 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{8710F623-E6C7-4EF9-9DAA-F6D0CE5E6EED}" 7 | EndProject 8 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{8699CFCC-A4E2-4DE0-90F5-A960ACD2E67F}" 9 | EndProject 10 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DatatableJS", "DatatableJS\DatatableJS.csproj", "{C9FEF38B-7625-4E71-8DD5-3FBD6BBF31CE}" 11 | EndProject 12 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DatatableJS.Net", "DatatableJS.Net\DatatableJS.Net.csproj", "{ACC1D84C-4261-498F-8E55-EF043F5F3D19}" 13 | EndProject 14 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DatatableJS.Data", "DatatableJS.Data\DatatableJS.Data.csproj", "{3583D1B8-6C7C-4EE3-8F10-1ACDB6B0ABC9}" 15 | EndProject 16 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DatatableJS.Data.UnitTest", "DatatableJS.Data.UnitTest\DatatableJS.Data.UnitTest.csproj", "{679C32BF-AA18-4576-A315-C1E8FED63240}" 17 | EndProject 18 | Global 19 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 20 | Debug|Any CPU = Debug|Any CPU 21 | Release|Any CPU = Release|Any CPU 22 | EndGlobalSection 23 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 24 | {C9FEF38B-7625-4E71-8DD5-3FBD6BBF31CE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 25 | {C9FEF38B-7625-4E71-8DD5-3FBD6BBF31CE}.Debug|Any CPU.Build.0 = Debug|Any CPU 26 | {C9FEF38B-7625-4E71-8DD5-3FBD6BBF31CE}.Release|Any CPU.ActiveCfg = Release|Any CPU 27 | {C9FEF38B-7625-4E71-8DD5-3FBD6BBF31CE}.Release|Any CPU.Build.0 = Release|Any CPU 28 | {ACC1D84C-4261-498F-8E55-EF043F5F3D19}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 29 | {ACC1D84C-4261-498F-8E55-EF043F5F3D19}.Debug|Any CPU.Build.0 = Debug|Any CPU 30 | {ACC1D84C-4261-498F-8E55-EF043F5F3D19}.Release|Any CPU.ActiveCfg = Release|Any CPU 31 | {ACC1D84C-4261-498F-8E55-EF043F5F3D19}.Release|Any CPU.Build.0 = Release|Any CPU 32 | {3583D1B8-6C7C-4EE3-8F10-1ACDB6B0ABC9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 33 | {3583D1B8-6C7C-4EE3-8F10-1ACDB6B0ABC9}.Debug|Any CPU.Build.0 = Debug|Any CPU 34 | {3583D1B8-6C7C-4EE3-8F10-1ACDB6B0ABC9}.Release|Any CPU.ActiveCfg = Release|Any CPU 35 | {3583D1B8-6C7C-4EE3-8F10-1ACDB6B0ABC9}.Release|Any CPU.Build.0 = Release|Any CPU 36 | {679C32BF-AA18-4576-A315-C1E8FED63240}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 37 | {679C32BF-AA18-4576-A315-C1E8FED63240}.Debug|Any CPU.Build.0 = Debug|Any CPU 38 | {679C32BF-AA18-4576-A315-C1E8FED63240}.Release|Any CPU.ActiveCfg = Release|Any CPU 39 | {679C32BF-AA18-4576-A315-C1E8FED63240}.Release|Any CPU.Build.0 = Release|Any CPU 40 | EndGlobalSection 41 | GlobalSection(SolutionProperties) = preSolution 42 | HideSolutionNode = FALSE 43 | EndGlobalSection 44 | GlobalSection(NestedProjects) = preSolution 45 | {C9FEF38B-7625-4E71-8DD5-3FBD6BBF31CE} = {8710F623-E6C7-4EF9-9DAA-F6D0CE5E6EED} 46 | {ACC1D84C-4261-498F-8E55-EF043F5F3D19} = {8710F623-E6C7-4EF9-9DAA-F6D0CE5E6EED} 47 | {3583D1B8-6C7C-4EE3-8F10-1ACDB6B0ABC9} = {8710F623-E6C7-4EF9-9DAA-F6D0CE5E6EED} 48 | {679C32BF-AA18-4576-A315-C1E8FED63240} = {8699CFCC-A4E2-4DE0-90F5-A960ACD2E67F} 49 | EndGlobalSection 50 | GlobalSection(ExtensibilityGlobals) = postSolution 51 | SolutionGuid = {BE95672B-C0C8-4A6A-9AB6-A650A832CEE2} 52 | EndGlobalSection 53 | EndGlobal 54 | -------------------------------------------------------------------------------- /DatatableJS/Builders/CallbackBuilder.cs: -------------------------------------------------------------------------------- 1 | namespace DatatableJS 2 | { 3 | /// 4 | /// Generic callback builder class 5 | /// 6 | /// 7 | public class CallbackBuilder 8 | { 9 | private readonly GridBuilder _grid; 10 | 11 | /// 12 | /// Initializes a new instance of the class. 13 | /// 14 | /// 15 | public CallbackBuilder(GridBuilder grid) 16 | { 17 | _grid = grid; 18 | } 19 | 20 | /// 21 | /// Set createdRow function Reference: 22 | /// 23 | /// 24 | /// 25 | public CallbackBuilder CreatedRow(string functionName) 26 | { 27 | _grid._callBack.CreatedRow = functionName; 28 | return this; 29 | } 30 | 31 | /// 32 | /// Set drawCallback function Reference: 33 | /// 34 | /// 35 | /// 36 | public CallbackBuilder DrawCallback(string functionName) 37 | { 38 | _grid._callBack.DrawCallback = functionName; 39 | return this; 40 | } 41 | 42 | /// 43 | /// Set footerCallback function Reference: 44 | /// 45 | /// 46 | /// 47 | public CallbackBuilder FooterCallback(string functionName) 48 | { 49 | _grid._callBack.FooterCallback = functionName; 50 | return this; 51 | } 52 | 53 | /// 54 | /// Set formatNumber function Reference: 55 | /// 56 | /// 57 | /// 58 | public CallbackBuilder FormatNumber(string functionName) 59 | { 60 | _grid._callBack.FormatNumber = functionName; 61 | return this; 62 | } 63 | 64 | /// 65 | /// Set headerCallback function Reference: 66 | /// 67 | /// 68 | /// 69 | public CallbackBuilder HeaderCallback(string functionName) 70 | { 71 | _grid._callBack.HeaderCallback = functionName; 72 | return this; 73 | } 74 | 75 | /// 76 | /// Set infoCallback function Reference: 77 | /// 78 | /// 79 | /// 80 | public CallbackBuilder InfoCallback(string functionName) 81 | { 82 | _grid._callBack.InfoCallback = functionName; 83 | return this; 84 | } 85 | 86 | /// 87 | /// Set initComplete function Reference: 88 | /// 89 | /// 90 | /// 91 | public CallbackBuilder InitComplete(string functionName) 92 | { 93 | _grid._callBack.InitComplete = functionName; 94 | return this; 95 | } 96 | 97 | /// 98 | /// Set preDrawCallback function Reference: 99 | /// 100 | /// 101 | /// 102 | public CallbackBuilder PreDrawCallback(string functionName) 103 | { 104 | _grid._callBack.PreDrawCallback = functionName; 105 | return this; 106 | } 107 | 108 | /// 109 | /// Set rowCallback function Reference: 110 | /// 111 | /// 112 | /// 113 | public CallbackBuilder RowCallback(string functionName) 114 | { 115 | _grid._callBack.RowCallback = functionName; 116 | return this; 117 | } 118 | 119 | /// 120 | /// Set stateLoadCallback function Reference: 121 | /// 122 | /// 123 | /// 124 | public CallbackBuilder StateLoadCallback(string functionName) 125 | { 126 | _grid._callBack.StateLoadCallback = functionName; 127 | _grid._stateSave = true; 128 | return this; 129 | } 130 | 131 | /// 132 | /// Set stateLoadParams function Reference: 133 | /// 134 | /// 135 | /// 136 | public CallbackBuilder StateLoadParams(string functionName) 137 | { 138 | _grid._callBack.StateLoadParams = functionName; 139 | _grid._stateSave = true; 140 | return this; 141 | } 142 | 143 | /// 144 | /// Set stateLoaded function Reference: 145 | /// 146 | /// 147 | /// 148 | public CallbackBuilder StateLoaded(string functionName) 149 | { 150 | _grid._callBack.StateLoaded = functionName; 151 | _grid._stateSave = true; 152 | return this; 153 | } 154 | 155 | /// 156 | /// Set stateSaveCallback function Reference: 157 | /// 158 | /// 159 | /// 160 | public CallbackBuilder StateSaveCallback(string functionName) 161 | { 162 | _grid._callBack.StateSaveCallback = functionName; 163 | _grid._stateSave = true; 164 | return this; 165 | } 166 | 167 | /// 168 | /// Set stateSaveParams function Reference: 169 | /// 170 | /// 171 | /// 172 | public CallbackBuilder StateSaveParams(string functionName) 173 | { 174 | _grid._callBack.StateSaveParams = functionName; 175 | _grid._stateSave = true; 176 | return this; 177 | } 178 | } 179 | } 180 | -------------------------------------------------------------------------------- /DatatableJS/Builders/ColReorderBuilder.cs: -------------------------------------------------------------------------------- 1 | namespace DatatableJS 2 | { 3 | /// 4 | /// Generic col reorder builder class 5 | /// 6 | /// 7 | public class ColReorderBuilder 8 | { 9 | private readonly GridBuilder _grid; 10 | 11 | /// 12 | /// Initializes a new instance of the class. 13 | /// 14 | /// 15 | public ColReorderBuilder(GridBuilder grid) 16 | { 17 | _grid = grid; 18 | } 19 | 20 | /// 21 | /// Initial enablement state of ColReorder. Default value is "true". Reference: 22 | /// 23 | /// true 24 | /// 25 | public ColReorderBuilder Enable(bool value) 26 | { 27 | _grid._colReorder.Settings = true; 28 | _grid._colReorder.Enable = value; 29 | return this; 30 | } 31 | 32 | /// 33 | /// Disallow x columns from reordering (counting from the left). Default is "0". Reference: 34 | /// 35 | /// 0 36 | /// 37 | public ColReorderBuilder FixedColumnsLeft(int value) 38 | { 39 | _grid._colReorder.Settings = true; 40 | _grid._colReorder.FixedColumnsLeft = value; 41 | return this; 42 | } 43 | 44 | /// 45 | /// Disallow x columns from reordering (counting from the right). Default is "0". Reference: 46 | /// 47 | /// 0 48 | /// 49 | public ColReorderBuilder FixedColumnsRight(int value) 50 | { 51 | _grid._colReorder.Settings = true; 52 | _grid._colReorder.FixedColumnsRight = value; 53 | return this; 54 | } 55 | 56 | /// 57 | /// Set a default order for the columns in the table. Reference: 58 | /// 59 | /// 60 | /// 61 | public ColReorderBuilder Order(params int[] value) 62 | { 63 | _grid._colReorder.Settings = true; 64 | _grid._colReorder.Order = $"[{string.Join(",", value)}]"; 65 | return this; 66 | } 67 | 68 | /// 69 | /// Enable / disable live reordering of columns during a drag. Default is "true". Reference: 70 | /// 71 | /// 72 | /// 73 | public ColReorderBuilder RealTime(bool value) 74 | { 75 | _grid._colReorder.Settings = true; 76 | _grid._colReorder.RealTime = value; 77 | return this; 78 | } 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /DatatableJS/Builders/ColumnBuilder.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel.DataAnnotations; 4 | using System.Linq; 5 | using System.Linq.Expressions; 6 | using System.Reflection; 7 | 8 | namespace DatatableJS 9 | { 10 | /// 11 | /// Generic column builder class. 12 | /// 13 | /// 14 | public class ColumnBuilder 15 | { 16 | private readonly GridBuilder _grid; 17 | private ColumnDefinition _column { get; set; } 18 | 19 | /// 20 | /// Initializes a new instance of the class. 21 | /// 22 | /// The grid. 23 | public ColumnBuilder(GridBuilder grid) 24 | { 25 | _grid = grid; 26 | } 27 | 28 | /// 29 | /// Make a column with defined type properties. 30 | /// 31 | /// The type of the property. 32 | /// The property. 33 | /// 34 | public ColumnBuilder Field(Expression> property) 35 | { 36 | var member = property.Body as MemberExpression; 37 | _column = new ColumnDefinition 38 | { 39 | Data = ExpressionHelpers.PropertyName(property), 40 | Title = member.Member.GetCustomAttribute()?.Name ?? ExpressionHelpers.PropertyName(property), 41 | Render = member.Member.GetCustomAttribute() != null ? $@"moment(data).format('{member.Member.GetCustomAttribute().DataFormatString}')" : null, 42 | Type = ((PropertyInfo)member.Member).PropertyType 43 | }; 44 | _grid._columns.Add(_column); 45 | return this; 46 | } 47 | 48 | /// 49 | /// Set column title. 50 | /// 51 | /// 52 | /// 53 | public ColumnBuilder Title(string title) 54 | { 55 | _column.Title = title; 56 | return this; 57 | } 58 | 59 | /// 60 | /// Set column visible or hidden, default is true. 61 | /// 62 | /// 63 | /// 64 | public ColumnBuilder Visible(bool isVisible) 65 | { 66 | _column.Visible = isVisible; 67 | _column.Orderable = false; 68 | _column.Searchable = false; 69 | return this; 70 | } 71 | 72 | /// 73 | /// Set column orderable or not, default is true. 74 | /// 75 | /// 76 | /// 77 | public ColumnBuilder Orderable(bool isOrderable) 78 | { 79 | _column.Orderable = isOrderable; 80 | return this; 81 | } 82 | 83 | /// 84 | /// Set column searchable or not, default is true. 85 | /// 86 | /// 87 | /// 88 | public ColumnBuilder Searchable(bool isSearchable) 89 | { 90 | _column.Searchable = isSearchable; 91 | return this; 92 | } 93 | 94 | /// 95 | /// Set column width percentage. 96 | /// 97 | /// 98 | /// 99 | public ColumnBuilder Width(int width) 100 | { 101 | _column.Width = width; 102 | return this; 103 | } 104 | 105 | /// 106 | /// Set css class of column. 107 | /// 108 | /// 109 | /// 110 | public ColumnBuilder Class(string className) 111 | { 112 | _column.ClassName = className; 113 | return this; 114 | } 115 | 116 | /// 117 | /// Set default value for null data 118 | /// 119 | /// 120 | /// 121 | public ColumnBuilder DefaultContent(string defaultContent) 122 | { 123 | _column.DefaultContent = defaultContent; 124 | return this; 125 | } 126 | 127 | /// 128 | /// Set a jquery datatable date format. 129 | /// 130 | /// 131 | /// 132 | public ColumnBuilder Format(string format) 133 | { 134 | _column.Render = $@"moment(data).format('{format}')"; 135 | return this; 136 | } 137 | 138 | /// 139 | /// Customize column template using "data" for comparison. 140 | /// 141 | /// 142 | /// 143 | public ColumnBuilder Template(string template) 144 | { 145 | _column.Render = template; 146 | return this; 147 | } 148 | 149 | /// 150 | /// Define a link or button. 151 | /// 152 | /// 153 | /// 154 | /// 155 | /// 156 | /// 157 | /// 158 | /// 159 | public ColumnBuilder Command(Expression> property, string onClick, string iconClass, string btnClass, string text) 160 | { 161 | _column = new ColumnDefinition 162 | { 163 | Width = 1, 164 | Data = ExpressionHelpers.PropertyName(property), 165 | Orderable = false, 166 | Searchable = false, 167 | Render = $@"''+{(string.IsNullOrEmpty(text) ? (string.IsNullOrEmpty(iconClass) ? "data" : "''") : string.Format("' {0}'", text))}+''" 168 | }; 169 | _grid._columns.Add(_column); 170 | return this; 171 | } 172 | 173 | /// 174 | /// Define a link or button. 175 | /// 176 | /// 177 | /// 178 | /// 179 | /// 180 | /// 181 | /// 182 | public ColumnBuilder Command(Expression> property, string onClick, string iconClass, string btnClass) 183 | { 184 | return Command(property, onClick, iconClass, btnClass, ""); 185 | } 186 | 187 | /// 188 | /// Define a link or button. 189 | /// 190 | /// 191 | /// 192 | /// 193 | /// 194 | /// 195 | public ColumnBuilder Command(Expression> property, string onClick, string iconClass) 196 | { 197 | return Command(property, onClick, iconClass, "", ""); 198 | } 199 | 200 | /// 201 | /// Define a link or button. 202 | /// 203 | /// 204 | /// 205 | /// 206 | /// 207 | public ColumnBuilder Command(Expression> property, string onClick) 208 | { 209 | return Command(property, onClick, "", "", ""); 210 | } 211 | 212 | /// 213 | /// Add multiple command to define button group. 214 | /// 215 | /// 216 | /// 217 | /// 218 | /// 219 | /// 220 | /// 221 | /// 222 | public ColumnBuilder Commands(Expression> property, IEnumerable commands, string btnText, string btnClass, string iconClass) 223 | { 224 | _column = new ColumnDefinition 225 | { 226 | Width = 1, 227 | Data = ExpressionHelpers.PropertyName(property), 228 | Orderable = false, 229 | Searchable = false, 230 | }; 231 | _column.Render = $@"'
'+ 232 | ''+ 235 | '
'+ 236 | {string.Join(Environment.NewLine, 237 | commands.Select(a => $@"'{a.Text}'+"))} 238 | '
'+ 239 | '
'"; 240 | _grid._columns.Add(_column); 241 | return this; 242 | } 243 | 244 | /// 245 | /// Add multiple command to define button group. 246 | /// 247 | /// 248 | /// 249 | /// 250 | /// 251 | public ColumnBuilder Commands(Expression> property, IEnumerable commands) 252 | { 253 | return Commands(property, commands, null, "btn-default", "caret"); 254 | } 255 | 256 | /// 257 | /// Add multiple command to define button group. 258 | /// 259 | /// 260 | /// 261 | /// 262 | /// 263 | /// 264 | public ColumnBuilder Commands(Expression> property, IEnumerable commands, string btnText) 265 | { 266 | return Commands(property, commands, btnText, "btn-default", "caret"); 267 | } 268 | 269 | /// 270 | /// Add multiple command to define button group. 271 | /// 272 | /// 273 | /// 274 | /// 275 | /// 276 | /// 277 | /// 278 | public ColumnBuilder Commands(Expression> property, IEnumerable commands, string btnText, string btnClass) 279 | { 280 | return Commands(property, commands, btnText, btnClass, "caret"); 281 | } 282 | } 283 | } 284 | -------------------------------------------------------------------------------- /DatatableJS/Builders/FilterBuilder.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq.Expressions; 3 | 4 | namespace DatatableJS 5 | { 6 | /// 7 | /// Generic filter builder class. 8 | /// 9 | /// 10 | public class FilterBuilder 11 | { 12 | private readonly GridBuilder _grid; 13 | private FilterModel _filter { get; set; } 14 | 15 | /// 16 | /// Initializes a new instance of the class. 17 | /// 18 | /// The grid. 19 | public FilterBuilder(GridBuilder grid) 20 | { 21 | _grid = grid; 22 | } 23 | 24 | /// 25 | /// Adds the specified property for filter. 26 | /// 27 | /// The type of the property. 28 | /// The property. 29 | /// 30 | public FilterBuilder Add(Expression> property) 31 | { 32 | _filter = new FilterModel 33 | { 34 | Field = ExpressionHelpers.PropertyName(property), 35 | }; 36 | return this; 37 | } 38 | 39 | /// 40 | /// Equals the specified value. 41 | /// 42 | /// The value. 43 | /// 44 | public FilterBuilder Equal(object value) 45 | { 46 | _filter.Operand = Operand.Equal; 47 | _filter.Value = value.ToString(); 48 | _grid._filters.Add(_filter); 49 | return this; 50 | } 51 | 52 | /// 53 | /// Nots the equal. 54 | /// 55 | /// The value. 56 | /// 57 | public FilterBuilder NotEqual(object value) 58 | { 59 | _filter.Operand = Operand.NotEqual; 60 | _filter.Value = value.ToString(); 61 | _grid._filters.Add(_filter); 62 | return this; 63 | } 64 | 65 | /// 66 | /// Greaters the than. 67 | /// 68 | /// The value. 69 | /// 70 | public FilterBuilder GreaterThan(object value) 71 | { 72 | _filter.Operand = Operand.GreaterThan; 73 | _filter.Value = value.ToString(); 74 | _grid._filters.Add(_filter); 75 | return this; 76 | } 77 | 78 | /// 79 | /// Determines whether this instance contains the object. 80 | /// 81 | /// The value. 82 | /// 83 | public FilterBuilder Contains(object value) 84 | { 85 | _filter.Operand = Operand.Contains; 86 | _filter.Value = value.ToString(); 87 | _grid._filters.Add(_filter); 88 | return this; 89 | } 90 | 91 | /// 92 | /// Endses the with. 93 | /// 94 | /// The value. 95 | /// 96 | public FilterBuilder EndsWith(object value) 97 | { 98 | _filter.Operand = Operand.EndsWith; 99 | _filter.Value = value.ToString(); 100 | _grid._filters.Add(_filter); 101 | return this; 102 | } 103 | 104 | /// 105 | /// Greaters the than or equal. 106 | /// 107 | /// The value. 108 | /// 109 | public FilterBuilder GreaterThanOrEqual(object value) 110 | { 111 | _filter.Operand = Operand.GreaterThanOrEqual; 112 | _filter.Value = value.ToString(); 113 | _grid._filters.Add(_filter); 114 | return this; 115 | } 116 | 117 | /// 118 | /// Lesses the than. 119 | /// 120 | /// The value. 121 | /// 122 | public FilterBuilder LessThan(object value) 123 | { 124 | _filter.Operand = Operand.LessThan; 125 | _filter.Value = value.ToString(); 126 | _grid._filters.Add(_filter); 127 | return this; 128 | } 129 | 130 | /// 131 | /// Lesses the than or equal. 132 | /// 133 | /// The value. 134 | /// 135 | public FilterBuilder LessThanOrEqual(object value) 136 | { 137 | _filter.Operand = Operand.LessThanOrEqual; 138 | _filter.Value = value.ToString(); 139 | _grid._filters.Add(_filter); 140 | return this; 141 | } 142 | 143 | /// 144 | /// Startses the with. 145 | /// 146 | /// The value. 147 | /// 148 | public FilterBuilder StartsWith(object value) 149 | { 150 | _filter.Operand = Operand.StartsWith; 151 | _filter.Value = value.ToString(); 152 | _grid._filters.Add(_filter); 153 | return this; 154 | } 155 | } 156 | } 157 | -------------------------------------------------------------------------------- /DatatableJS/Builders/LanguageBuilder.cs: -------------------------------------------------------------------------------- 1 | namespace DatatableJS 2 | { 3 | /// 4 | /// Generic language builder class 5 | /// 6 | /// 7 | public class LanguageBuilder 8 | { 9 | private readonly GridBuilder _grid; 10 | 11 | /// 12 | /// Initializes a new instance of the class. 13 | /// 14 | /// 15 | public LanguageBuilder(GridBuilder grid) 16 | { 17 | _grid = grid; 18 | } 19 | 20 | /// 21 | /// Set the decimal place character. Reference: 22 | /// 23 | /// 24 | /// 25 | public LanguageBuilder Decimal(string place) 26 | { 27 | _grid._language.Decimal = place; 28 | return this; 29 | } 30 | 31 | /// 32 | /// This string is shown when the table is empty of data (regardless of filtering). Reference: 33 | /// 34 | /// No data available in table 35 | /// 36 | public LanguageBuilder EmptyTable(string message) 37 | { 38 | _grid._language.EmptyTable = message; 39 | return this; 40 | } 41 | 42 | /// 43 | /// This string gives information to the end user about the information that is current on display on the page. Reference: 44 | /// 45 | /// Showing _START_ to _END_ of _TOTAL_ entries 46 | /// 47 | public LanguageBuilder Info(string message) 48 | { 49 | _grid._language.Info = message; 50 | return this; 51 | } 52 | 53 | /// 54 | /// Display information string for when the table is empty. Reference: 55 | /// 56 | /// Showing 0 to 0 of 0 entries 57 | /// 58 | public LanguageBuilder InfoEmpty(string message) 59 | { 60 | _grid._language.InfoEmpty = message; 61 | return this; 62 | } 63 | 64 | /// 65 | /// When a user filters the information in a table, this string is appended to the information (info) to give an idea of how strong the filtering is. Reference: 66 | /// 67 | /// (filtered from _MAX_ total entries) 68 | /// 69 | public LanguageBuilder InfoFiltered(string message) 70 | { 71 | _grid._language.InfoFiltered = message; 72 | return this; 73 | } 74 | 75 | /// 76 | /// If can be useful to append extra information to the info string at times, and this variable does exactly that. Reference: 77 | /// 78 | /// 79 | /// 80 | public LanguageBuilder InfoPostFix(string message) 81 | { 82 | _grid._language.InfoPostFix = message; 83 | return this; 84 | } 85 | 86 | /// 87 | /// The thousands separator option is used for output of information only. Reference: 88 | /// 89 | /// , 90 | /// 91 | public LanguageBuilder Thousands(string place) 92 | { 93 | _grid._language.Thousands = place; 94 | return this; 95 | } 96 | 97 | /// 98 | /// Detail the action that will be taken when the drop down menu for the pagination length option is changed. Reference: 99 | /// 100 | /// Show _MENU_ entries 101 | /// 102 | public LanguageBuilder LengthMenu(string message) 103 | { 104 | _grid._language.LengthMenu = message; 105 | return this; 106 | } 107 | 108 | /// 109 | /// This message is shown in an empty row in the table to indicate to the end user the the data is being loaded. Reference: 110 | /// 111 | /// Loading... 112 | /// 113 | public LanguageBuilder LoadingRecords(string message) 114 | { 115 | _grid._language.LoadingRecords = message; 116 | return this; 117 | } 118 | 119 | /// 120 | /// Text that is displayed when the table is processing a user action (usually a sort command or similar). Reference: 121 | /// 122 | /// {Empty string} 123 | /// 124 | public LanguageBuilder Processing(string message) 125 | { 126 | _grid._language.Processing = message; 127 | return this; 128 | } 129 | 130 | /// 131 | /// Sets the string that is used for DataTables filtering input control. Reference: 132 | /// 133 | /// Search: 134 | /// 135 | public LanguageBuilder Search(string message) 136 | { 137 | _grid._language.Search = message; 138 | return this; 139 | } 140 | 141 | /// 142 | /// Text shown inside the table records when the is no information to be displayed after filtering. Reference: 143 | /// 144 | /// No matching records found 145 | /// 146 | public LanguageBuilder ZeroRecords(string message) 147 | { 148 | _grid._language.ZeroRecords = message; 149 | return this; 150 | } 151 | 152 | /// 153 | /// Pagination string used by DataTables for the built-in pagination control types. Reference: 154 | /// 155 | /// First 156 | /// Last 157 | /// Next 158 | /// Previous 159 | /// 160 | public LanguageBuilder Paginate(string first, string last, string next, string previous) 161 | { 162 | _grid._language.Paginate.First = first; 163 | _grid._language.Paginate.Last = last; 164 | _grid._language.Paginate.Next = next; 165 | _grid._language.Paginate.Previous = previous; 166 | return this; 167 | } 168 | 169 | /// 170 | /// Language strings used for WAI-ARIA specific attributes. Reference: 171 | /// 172 | /// : activate to sort column ascending 173 | /// : activate to sort column descending 174 | /// 175 | public LanguageBuilder Aria(string sortAscending, string sortDescending) 176 | { 177 | _grid._language.Aria.SortAscending = sortAscending; 178 | _grid._language.Aria.SortDescending = sortDescending; 179 | return this; 180 | } 181 | } 182 | } 183 | -------------------------------------------------------------------------------- /DatatableJS/Builders/OrderBuilder.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | using System.Linq.Expressions; 4 | using DatatableJS.Exceptions; 5 | 6 | namespace DatatableJS 7 | { 8 | /// 9 | /// Generic order builder class. 10 | /// 11 | /// 12 | public class OrderBuilder 13 | { 14 | private readonly GridBuilder _grid; 15 | private OrderModel _order { get; set; } 16 | 17 | /// 18 | /// Initializes a new instance of the class. 19 | /// 20 | /// The grid. 21 | public OrderBuilder(GridBuilder grid) 22 | { 23 | _grid = grid; 24 | } 25 | 26 | /// 27 | /// Adds the specified property for default ordering. 28 | /// 29 | /// The type of the property. 30 | /// The property. 31 | /// The order. 32 | /// 33 | public OrderBuilder Add(Expression> property, OrderBy orderBy) 34 | { 35 | var propertyName = ExpressionHelpers.PropertyName(property); 36 | 37 | var column = _grid._columns 38 | .Where(c => c.Data != null && c.Data.Equals(propertyName)) 39 | .FirstOrDefault(); 40 | 41 | if (column == null) 42 | { 43 | throw new ColumnNotFoundException(string.Format("Column not found for property {0}", propertyName)); 44 | } 45 | 46 | var columnIndex = _grid._columns.IndexOf(column); 47 | 48 | _order = new OrderModel 49 | { 50 | Field = propertyName, 51 | Column = columnIndex, 52 | OrderBy = orderBy 53 | }; 54 | _grid._orders.Add(_order); 55 | 56 | return this; 57 | } 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /DatatableJS/DatatableJS.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | netstandard2.0 5 | Emrah KONDUR 6 | Emrah KONDUR 7 | DatatableJS is a helper to create a grid with Jquery Datatable and provides an extension to retrive data generically from any IQueryable list. It possible to use many Jquery Datatables features with Tag Helper. It gives serverside or client side options. 8 | https://github.com/ekondur/DatatableJS 9 | LICENSE.md 10 | https://www.datatablejs.net/ 11 | README.md 12 | https://github.com/ekondur/DatatableJS 13 | git 14 | C#, Tag Helper, Jquery Datatables, Entity Framework, Mvc, Net Core 15 | Fixed NRE issue during ordering 16 | true 17 | 3.9.1 18 | datatable-js.png 19 | 20 | true 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | True 33 | 34 | 35 | 36 | True 37 | 38 | 39 | 40 | True 41 | 42 | 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /DatatableJS/Definitions/ColumnDefinition.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace DatatableJS 4 | { 5 | #pragma warning disable CS1591 // Missing XML comment for publicly visible type or member 6 | public class ColumnDefinition 7 | { 8 | public string Data { get; set; } 9 | public string Title { get; set; } 10 | public bool Visible { get; set; } = true; 11 | public bool Searchable { get; set; } = true; 12 | public bool Orderable { get; set; } = true; 13 | public int Width { get; set; } 14 | public string ClassName { get; set; } = ""; 15 | public string Render { get; set; } = "data"; 16 | public Type Type { get; set; } 17 | public string DefaultContent { get; set; } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /DatatableJS/Exceptions/ColumnNotFoundException.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace DatatableJS.Exceptions 4 | { 5 | /// 6 | /// Exception thrown when a column is not found. 7 | /// 8 | public class ColumnNotFoundException : Exception 9 | { 10 | /// 11 | /// Create a new exception of type ColumnNotFoundException. 12 | /// 13 | public ColumnNotFoundException() 14 | { 15 | } 16 | 17 | /// 18 | /// Create a new exception of type ColumnNotFoundException. 19 | /// 20 | /// 21 | public ColumnNotFoundException(string message) 22 | : base(message) 23 | { 24 | } 25 | 26 | /// 27 | /// Create a new exception of type ColumnNotFoundException. 28 | /// 29 | /// 30 | /// 31 | public ColumnNotFoundException(string message, Exception inner) 32 | : base(message, inner) 33 | { 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /DatatableJS/Helpers/AriaHelper.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Razor.TagHelpers; 2 | 3 | namespace DatatableJS.Helpers 4 | { 5 | /// 6 | /// Language strings used for WAI-ARIA specific attributes. 7 | /// 8 | [HtmlTargetElement("aria", ParentTag = "language", TagStructure = TagStructure.WithoutEndTag)] 9 | public class AriaHelper : TagHelper 10 | { 11 | /// 12 | /// Default is ': activate to sort column ascending'. 13 | /// 14 | public string SortAscending { get; set; } 15 | 16 | /// 17 | /// Default is ': activate to sort column descending'. 18 | /// 19 | public string SortDescending { get; set; } 20 | 21 | /// 22 | /// Process 23 | /// 24 | /// 25 | /// 26 | public override void Process(TagHelperContext context, TagHelperOutput output) 27 | { 28 | output.Content.Clear(); 29 | var aria = CommonHelpers.GetGrid(context).Language.Aria; 30 | aria.SortAscending = SortAscending; 31 | aria.SortDescending = SortDescending; 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /DatatableJS/Helpers/CallbackHelper.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Razor.TagHelpers; 2 | 3 | namespace DatatableJS.Helpers 4 | { 5 | /// 6 | /// Set callback functions. Reference: 7 | /// 8 | [HtmlTargetElement("callbacks", ParentTag = "js-datatable", TagStructure = TagStructure.WithoutEndTag)] 9 | public class CallbackHelper : TagHelper 10 | { 11 | /// 12 | /// Set createdRow function Reference: 13 | /// 14 | public string CreatedRow { get; set; } 15 | 16 | /// 17 | /// Set drawCallback function Reference: 18 | /// 19 | public string DrawCallback { get; set; } 20 | 21 | /// 22 | /// Set footerCallback function Reference: 23 | /// 24 | public string FooterCallback { get; set; } 25 | 26 | /// 27 | /// Set formatNumber function Reference: 28 | /// 29 | public string FormatNumber { get; set; } 30 | 31 | /// 32 | /// Set headerCallback function Reference: 33 | /// 34 | public string HeaderCallback { get; set; } 35 | 36 | /// 37 | /// Set infoCallback function Reference: 38 | /// 39 | public string InfoCallback { get; set; } 40 | 41 | /// 42 | /// Set initComplete function Reference: 43 | /// 44 | public string InitComplete { get; set; } 45 | 46 | /// 47 | /// Set preDrawCallback function Reference: 48 | /// 49 | public string PreDrawCallback { get; set; } 50 | 51 | /// 52 | /// Set rowCallback function Reference: 53 | /// 54 | public string RowCallback { get; set; } 55 | 56 | /// 57 | /// Set stateLoadCallback function Reference: 58 | /// 59 | public string StateLoadCallback { get; set; } 60 | 61 | /// 62 | /// Set stateLoadParams function Reference: 63 | /// 64 | public string StateLoadParams { get; set; } 65 | 66 | /// 67 | /// Set stateLoaded function Reference: 68 | /// 69 | public string StateLoaded { get; set; } 70 | 71 | /// 72 | /// Set stateSaveCallback function Reference: 73 | /// 74 | public string StateSaveCallback { get; set; } 75 | 76 | /// 77 | /// Set stateSaveParams function Reference: 78 | /// 79 | public string StateSaveParams { get; set; } 80 | 81 | /// 82 | /// Process 83 | /// 84 | /// 85 | /// 86 | public override void Process(TagHelperContext context, TagHelperOutput output) 87 | { 88 | output.Content.Clear(); 89 | var grid = CommonHelpers.GetGrid(context); 90 | grid.Callback.CreatedRow = CreatedRow; 91 | grid.Callback.InitComplete = InitComplete; 92 | grid.Callback.DrawCallback = DrawCallback; 93 | grid.Callback.FooterCallback = FooterCallback; 94 | grid.Callback.FormatNumber = FormatNumber; 95 | grid.Callback.HeaderCallback = HeaderCallback; 96 | grid.Callback.InfoCallback = InfoCallback; 97 | grid.Callback.PreDrawCallback = PreDrawCallback; 98 | grid.Callback.RowCallback = RowCallback; 99 | grid.Callback.StateLoadCallback = StateLoadCallback; 100 | grid.Callback.StateLoadParams = StateLoadParams; 101 | grid.Callback.StateLoaded = StateLoaded; 102 | grid.Callback.StateSaveCallback = StateSaveCallback; 103 | grid.Callback.StateSaveParams = StateSaveParams; 104 | grid.StateSave = !string.IsNullOrEmpty(StateLoadCallback) || !string.IsNullOrEmpty(StateLoadParams) 105 | || !string.IsNullOrEmpty(StateLoaded) || !string.IsNullOrEmpty(StateSaveCallback) || !string.IsNullOrEmpty(StateSaveParams); 106 | } 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /DatatableJS/Helpers/CaptionsHelper.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Razor.TagHelpers; 2 | 3 | namespace DatatableJS 4 | { 5 | /// 6 | /// Define table top or bottom captions. 7 | /// 8 | [HtmlTargetElement("captions", ParentTag = "js-datatable", TagStructure = TagStructure.WithoutEndTag)] 9 | public class CaptionsHelper : TagHelper 10 | { 11 | /// 12 | /// Define table top caption. 13 | /// 14 | public string Top { get; set; } 15 | 16 | /// 17 | /// Define table bottom caption. 18 | /// 19 | public string Bottom { get; set; } 20 | 21 | /// 22 | /// Process 23 | /// 24 | /// 25 | /// 26 | public override void Process(TagHelperContext context, TagHelperOutput output) 27 | { 28 | output.Content.Clear(); 29 | var captions = CommonHelpers.GetGrid(context).Captions; 30 | captions.Top = Top; 31 | captions.Bottom = Bottom; 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /DatatableJS/Helpers/ColReorderHelper.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Razor.TagHelpers; 2 | 3 | namespace DatatableJS.Helpers 4 | { 5 | /// 6 | /// Define table col reorder. 7 | /// 8 | [HtmlTargetElement("col-reorder", ParentTag = "js-datatable", TagStructure = TagStructure.WithoutEndTag)] 9 | public class ColReorderHelper : TagHelper 10 | { 11 | /// 12 | /// Initial enablement state of ColReorder. Default value is "true". Reference: 13 | /// 14 | public bool Enable { get; set; } = true; 15 | 16 | /// 17 | /// Disallow x columns from reordering (counting from the left). Default is "0". Reference: 18 | /// 19 | public int FixedColumnsLeft { get; set; } 20 | 21 | /// 22 | /// Disallow x columns from reordering (counting from the right). Default is "0". Reference: 23 | /// 24 | public int FixedColumnsRight { get; set; } 25 | 26 | /// 27 | /// Set a default order for the columns in the table. Reference: 28 | /// 29 | public new string Order { get; set; } = "null"; 30 | 31 | /// 32 | /// Enable / disable live reordering of columns during a drag. Default is "true". Reference: 33 | /// 34 | public bool RealTime { get; set; } = true; 35 | 36 | /// 37 | /// Process 38 | /// 39 | /// 40 | /// 41 | public override void Process(TagHelperContext context, TagHelperOutput output) 42 | { 43 | output.Content.Clear(); 44 | var colReorder = CommonHelpers.GetGrid(context).ColReorder; 45 | colReorder.Settings = true; 46 | colReorder.Enable = Enable; 47 | colReorder.FixedColumnsLeft = FixedColumnsLeft; 48 | colReorder.FixedColumnsRight = FixedColumnsRight; 49 | colReorder.Order = Order; 50 | colReorder.RealTime = RealTime; 51 | } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /DatatableJS/Helpers/ColumnsHelper.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Razor.TagHelpers; 2 | 3 | namespace DatatableJS 4 | { 5 | /// 6 | /// Columns builder. 7 | /// 8 | [HtmlTargetElement("columns", ParentTag = "js-datatable")] 9 | public class ColumnsHelper : TagHelper 10 | { 11 | /// 12 | /// Process 13 | /// 14 | /// 15 | /// 16 | public override void Process(TagHelperContext context, TagHelperOutput output) 17 | { 18 | output.TagName = "thead"; 19 | output.TagMode = TagMode.StartTagAndEndTag; 20 | output.PreContent.SetHtmlContent(""); 21 | output.PostContent.SetHtmlContent(""); 22 | } 23 | } 24 | 25 | /// 26 | /// Column builder. 27 | /// 28 | [HtmlTargetElement("column", ParentTag = "columns", TagStructure = TagStructure.WithoutEndTag)] 29 | public class ColumnHelper : TagHelper 30 | { 31 | /// 32 | /// Make a column with defined type properties. 33 | /// 34 | public string Field { get; set; } 35 | 36 | /// 37 | /// Set column title. 38 | /// 39 | public string Title { get; set; } 40 | 41 | /// 42 | /// Set column visible or hidden, default is true. 43 | /// 44 | public bool Visible { get; set; } = true; 45 | 46 | /// 47 | /// Set column orderable or not, default is true. 48 | /// 49 | public bool Orderable { get; set; } = true; 50 | 51 | /// 52 | /// Set column searchable or not, default is true. 53 | /// 54 | public bool Searchable { get; set; } = true; 55 | 56 | /// 57 | /// Set column width percentage. 58 | /// 59 | public int Width { get; set; } 60 | 61 | /// 62 | /// Set css class of column. 63 | /// 64 | public string ClassName { get; set; } = ""; 65 | 66 | /// 67 | /// Set default value for null data 68 | /// 69 | public string DefaultContent { get; set; } 70 | 71 | /// 72 | /// Process 73 | /// 74 | /// 75 | /// 76 | public override void Process(TagHelperContext context, TagHelperOutput output) 77 | { 78 | output.TagName = "th"; 79 | output.TagMode = TagMode.StartTagAndEndTag; 80 | output.Content.Append(Title ?? Field); 81 | 82 | var grid = CommonHelpers.GetGrid(context); 83 | grid.Columns.Add(new ColumnModel 84 | { 85 | Data = Field, 86 | Visible = Visible, 87 | Searchable = Searchable, 88 | Orderable = Orderable, 89 | Width = Width, 90 | ClassName = ClassName, 91 | DefaultContent = DefaultContent 92 | }); 93 | } 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /DatatableJS/Helpers/CommandHelper.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Razor.TagHelpers; 2 | 3 | namespace DatatableJS 4 | { 5 | /// 6 | /// Add a command to define button. 7 | /// 8 | [HtmlTargetElement("command-item", ParentTag = "columns")] 9 | public class CommandHelper : TagHelper 10 | { 11 | public string Field { get; set; } 12 | public string Title { get; set; } 13 | public string OnClick { get; set; } 14 | public string Text { get; set; } 15 | public string IconClass { get; set; } 16 | public string BtnClass { get; set; } 17 | public int Width { get; set; } = 1; 18 | 19 | /// 20 | /// Process 21 | /// 22 | /// 23 | /// 24 | public override void Process(TagHelperContext context, TagHelperOutput output) 25 | { 26 | output.TagName = "th"; 27 | output.TagMode = TagMode.StartTagAndEndTag; 28 | output.Content.Append(Title ?? "#"); 29 | 30 | var grid = CommonHelpers.GetGrid(context); 31 | grid.Columns.Add(new ColumnModel 32 | { 33 | Data = Field, 34 | Visible = true, 35 | Searchable = false, 36 | Orderable = false, 37 | Width = Width, 38 | Render = $@"''+{(string.IsNullOrEmpty(Text) ? (string.IsNullOrEmpty(IconClass) ? "data" : "''") : string.Format("' {0}'", Text))}+''" 39 | }); 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /DatatableJS/Helpers/CommandsHelper.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Razor.TagHelpers; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | 6 | namespace DatatableJS 7 | { 8 | /// 9 | /// Add multiple command to define button group. 10 | /// 11 | [HtmlTargetElement("commands", ParentTag = "columns")] 12 | public class CommandsHelper : TagHelper 13 | { 14 | public string Field { get; set; } 15 | public string Title { get; set; } 16 | public string Text { get; set; } 17 | public string BtnClass { get; set; } = "btn btn-secondary"; 18 | public int Width { get; set; } = 1; 19 | public string BtnId { get; set; } = "btn-group"; 20 | 21 | public IEnumerable Items { get; set; } = new List(); 22 | 23 | /// 24 | /// Process 25 | /// 26 | /// 27 | /// 28 | public override void Process(TagHelperContext context, TagHelperOutput output) 29 | { 30 | output.TagName = "th"; 31 | output.TagMode = TagMode.StartTagAndEndTag; 32 | output.Content.Append(Title ?? "#"); 33 | 34 | var grid = CommonHelpers.GetGrid(context); 35 | grid.Columns.Add(new ColumnModel 36 | { 37 | Data = Field, 38 | Visible = true, 39 | Searchable = false, 40 | Orderable = false, 41 | Width = Width, 42 | Render = $@"'
'+ 43 | ''+ 46 | '
'+ 47 | { 48 | string.Join(Environment.NewLine, 49 | Items.Select(a => $@"'{a.Text}'+"))} 50 | '
'+ 51 | '
'" 52 | }); 53 | } 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /DatatableJS/Helpers/CommonHelpers.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Razor.TagHelpers; 2 | using System; 3 | using System.ComponentModel; 4 | using System.Globalization; 5 | 6 | namespace DatatableJS 7 | { 8 | public static class CommonHelpers 9 | { 10 | public static string ToLowString(this bool b) 11 | { 12 | return b.ToString().ToLower(CultureInfo.InvariantCulture); 13 | } 14 | 15 | public static GridModel GetGrid(TagHelperContext context) 16 | { 17 | context.Items.TryGetValue("DataGrid", out object model); 18 | return (GridModel)model; 19 | } 20 | 21 | public static string GetEnumDescription(this Enum enumValue) 22 | { 23 | var fieldInfo = enumValue.GetType().GetField(enumValue.ToString()); 24 | 25 | var descriptionAttributes = (DescriptionAttribute[])fieldInfo.GetCustomAttributes(typeof(DescriptionAttribute), false); 26 | 27 | return descriptionAttributes.Length > 0 ? descriptionAttributes[0].Description : enumValue.ToString(); 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /DatatableJS/Helpers/DataSourceHelper.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Razor.TagHelpers; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | 5 | namespace DatatableJS 6 | { 7 | /// 8 | /// Set datasource properties 9 | /// 10 | [HtmlTargetElement("data-source", ParentTag = "js-datatable", TagStructure = TagStructure.WithoutEndTag)] 11 | public class DataSourceHelper : TagHelper 12 | { 13 | /// 14 | /// URL 15 | /// 16 | public string URL { get; set; } 17 | 18 | /// 19 | /// Set the action type, default type is GET. 20 | /// 21 | public HttpMethodType Method { get; set; } = HttpMethodType.GET; 22 | 23 | /// 24 | /// Enable Json Naming Policy as CamelCase. 25 | /// 26 | public bool CamelCase { get; set; } 27 | 28 | /// 29 | /// Disable or enable paging, default is true. 30 | /// 31 | public bool Paging { get; set; } = true; 32 | 33 | /// 34 | /// Enable server-side processing mode. 35 | /// 36 | public bool ServerSide { get; set; } 37 | 38 | /// 39 | /// Passing additional data to action set name of javascript function. 40 | /// 41 | public string Data { get; set; } 42 | 43 | /// 44 | /// Define table page length. 45 | /// 46 | public int PageLength { get; set; } = 10; 47 | 48 | /// 49 | /// Process 50 | /// 51 | /// 52 | /// 53 | public override void Process(TagHelperContext context, TagHelperOutput output) 54 | { 55 | output.Content.Clear(); 56 | var grid = CommonHelpers.GetGrid(context); 57 | grid.DataSource.URL = URL; 58 | grid.DataSource.Method = Method; 59 | grid.DataSource.Paging = Paging; 60 | grid.DataSource.Data = Data; 61 | grid.DataSource.ServerSide = ServerSide; 62 | grid.DataSource.PageLength = PageLength; 63 | grid.DataSource.CamelCase = CamelCase; 64 | 65 | if (!grid.LengthMenu._lengthMenuValues.Any()) 66 | { 67 | grid.LengthMenu._lengthMenuValues = new List { PageLength, PageLength * 2, PageLength * 3, PageLength * 4, PageLength * 5 }; 68 | grid.LengthMenu._lengthMenuDisplayedTexts = grid.LengthMenu._lengthMenuValues.Select(x => x.ToString()).ToList(); 69 | } 70 | } 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /DatatableJS/Helpers/FiltersHelper.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Razor.TagHelpers; 2 | 3 | namespace DatatableJS 4 | { 5 | /// 6 | /// Filter data with request. 7 | /// 8 | [HtmlTargetElement("filters", ParentTag = "js-datatable")] 9 | public class FiltersHelper : TagHelper 10 | { 11 | /// 12 | /// Process 13 | /// 14 | /// 15 | /// 16 | public override void Process(TagHelperContext context, TagHelperOutput output) 17 | { 18 | base.Process(context, output); 19 | } 20 | } 21 | 22 | /// 23 | /// Add a filter to request. 24 | /// 25 | [HtmlTargetElement("add", ParentTag = "filters", TagStructure = TagStructure.WithoutEndTag)] 26 | public class FilterHelper : TagHelper 27 | { 28 | public string Field { get; set; } 29 | public string Value { get; set; } 30 | public Operand Operand { get; set; } 31 | 32 | /// 33 | /// Process 34 | /// 35 | /// 36 | /// 37 | public override void Process(TagHelperContext context, TagHelperOutput output) 38 | { 39 | output.Content.Clear(); 40 | var grid = CommonHelpers.GetGrid(context); 41 | grid.Filters.Add(new FilterModel 42 | { 43 | Field = Field, 44 | Value = Value, 45 | Operand = Operand 46 | }); 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /DatatableJS/Helpers/FixedColumnsHelper.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Razor.TagHelpers; 2 | 3 | namespace DatatableJS 4 | { 5 | /// 6 | /// Fix the table columns from left or right. 7 | /// 8 | [HtmlTargetElement("fixed-columns", ParentTag = "js-datatable", TagStructure = TagStructure.WithoutEndTag)] 9 | public class FixedColumnsHelper : TagHelper 10 | { 11 | public int LeftColumns { get; set; } 12 | public int RightColumns { get; set; } 13 | 14 | /// 15 | /// Process 16 | /// 17 | /// 18 | /// 19 | public override void Process(TagHelperContext context, TagHelperOutput output) 20 | { 21 | output.Content.Clear(); 22 | var fixedColumns = CommonHelpers.GetGrid(context).FixedColumns; 23 | fixedColumns.LeftColumns = LeftColumns; 24 | fixedColumns.RightColumns = RightColumns; 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /DatatableJS/Helpers/GridHelper.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Razor.TagHelpers; 2 | using static System.Net.WebRequestMethods; 3 | 4 | namespace DatatableJS 5 | { 6 | /// 7 | /// Generic grid builder class. 8 | /// 9 | [HtmlTargetElement("js-datatable")] 10 | public class GridHelper : TagHelper 11 | { 12 | /// 13 | /// Default name is "DataGrid". 14 | /// 15 | public string Name { get; set; } = "DataGrid"; 16 | 17 | /// 18 | /// Disable or enable ordering, default is true. 19 | /// 20 | public bool Ordering { get; set; } = true; 21 | 22 | /// 23 | /// Disable or enable searching, default is true. 24 | /// 25 | public bool Searching { get; set; } = true; 26 | 27 | /// 28 | /// Enable or disable the display of a 'processing' indicator when the table is being processed, Default is true. 29 | /// 30 | public bool Processing { get; set; } = true; 31 | 32 | /// 33 | /// Enable horizontal scrolling. When a table is too wide to fit into a certain layout, or you have a large number of columns in the table, you can enable horizontal (x) scrolling to show the table in a viewport, which can be scrolled. 34 | /// 35 | public bool ScrollX { get; set; } 36 | 37 | /// 38 | /// Enable or disable state saving such as pagination position, display length, filtering and sorting information. 39 | /// 40 | public bool StateSave { get; set; } 41 | 42 | /// 43 | /// Enable control over displayed elements 44 | /// 45 | /// 46 | public string Dom { get; set; } 47 | 48 | /// 49 | /// Process 50 | /// 51 | /// 52 | /// 53 | public override void Process(TagHelperContext context, TagHelperOutput output) 54 | { 55 | output.TagName = "table"; 56 | output.TagMode = TagMode.StartTagAndEndTag; 57 | output.Attributes.SetAttribute("id", Name); 58 | output.Attributes.SetAttribute("style", "width:100%"); 59 | output.Attributes.SetAttribute("class", "display nowrap dataTable dtr-inline collapsed"); 60 | 61 | var grid = new GridModel 62 | { 63 | Name = Name, 64 | Ordering = Ordering, 65 | Searching = Searching, 66 | Processing = Processing, 67 | ScrollX = ScrollX, 68 | StateSave = StateSave, 69 | Dom = Dom 70 | }; 71 | 72 | context.Items.Add("DataGrid", grid); 73 | } 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /DatatableJS/Helpers/LanguageHelper.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Razor.TagHelpers; 2 | 3 | namespace DatatableJS 4 | { 5 | /// 6 | /// Language configuration options for DataTables. 7 | /// 8 | [HtmlTargetElement("language", ParentTag = "js-datatable")] 9 | public class LanguageHelper : TagHelper 10 | { 11 | /// 12 | /// Set language json source URL. 13 | /// 14 | public string URL { get; set; } 15 | 16 | /// 17 | /// Set the decimal place character. Reference: 18 | /// 19 | public string Decimal { get; set; } 20 | 21 | /// 22 | /// This string is shown when the table is empty of data (regardless of filtering). Reference: 23 | /// 24 | public string EmptyTable { get; set; } 25 | 26 | /// 27 | /// This string gives information to the end user about the information that is current on display on the page. Reference: 28 | /// 29 | public string Info { get; set; } 30 | 31 | /// 32 | /// Display information string for when the table is empty. Reference: 33 | /// 34 | public string InfoEmpty { get; set; } 35 | 36 | /// 37 | /// When a user filters the information in a table, this string is appended to the information (info) to give an idea of how strong the filtering is. Reference: 38 | /// 39 | public string InfoFiltered { get; set; } 40 | 41 | /// 42 | /// If can be useful to append extra information to the info string at times, and this variable does exactly that. Reference: 43 | /// 44 | public string InfoPostFix { get; set; } 45 | 46 | /// 47 | /// The thousands separator option is used for output of information only. Reference: 48 | /// 49 | public string Thousands { get; set; } 50 | 51 | /// 52 | /// Detail the action that will be taken when the drop down menu for the pagination length option is changed. Reference: 53 | /// 54 | public string LengthMenu { get; set; } 55 | 56 | /// 57 | /// This message is shown in an empty row in the table to indicate to the end user the the data is being loaded. Reference: 58 | /// 59 | public string LoadingRecords { get; set; } 60 | 61 | /// 62 | /// Text that is displayed when the table is processing a user action (usually a sort command or similar). Reference: 63 | /// 64 | public string Processing { get; set; } 65 | 66 | /// 67 | /// Sets the string that is used for DataTables filtering input control. Reference: 68 | /// 69 | public string Search { get; set; } 70 | 71 | /// 72 | /// Text shown inside the table records when the is no information to be displayed after filtering. Reference: 73 | /// 74 | public string ZeroRecords { get; set; } 75 | 76 | /// 77 | /// Process 78 | /// 79 | /// 80 | /// 81 | public override void Process(TagHelperContext context, TagHelperOutput output) 82 | { 83 | output.TagMode = TagMode.StartTagAndEndTag; 84 | var language = CommonHelpers.GetGrid(context).Language; 85 | language.URL = URL; 86 | language.Decimal = Decimal; 87 | language.EmptyTable = EmptyTable; 88 | language.Info = Info; 89 | language.InfoEmpty = InfoEmpty; 90 | language.InfoFiltered = InfoFiltered; 91 | language.InfoPostFix = InfoPostFix; 92 | language.Thousands = Thousands; 93 | language.LengthMenu = LengthMenu; 94 | language.LoadingRecords = LoadingRecords; 95 | language.Processing = Processing; 96 | language.Search = Search; 97 | language.ZeroRecords = ZeroRecords; 98 | } 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /DatatableJS/Helpers/LengthMenuHelper.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Razor.TagHelpers; 2 | using System.Linq; 3 | 4 | namespace DatatableJS.Helpers 5 | { 6 | /// 7 | /// Define table length menu. 8 | /// 9 | [HtmlTargetElement("length-menu", ParentTag = "js-datatable", TagStructure = TagStructure.WithoutEndTag)] 10 | public class LengthMenuHelper : TagHelper 11 | { 12 | /// 13 | /// Set the values of LengthMenu 14 | /// 15 | public int[] Values { get; set; } 16 | 17 | /// 18 | /// Add All option on LengthMenu 19 | /// 20 | public bool HasAll { get; set; } 21 | 22 | /// 23 | /// Set a text for LengtMenu All option, default is "All" 24 | /// 25 | public string AllText { get; set; } = "All"; 26 | 27 | /// 28 | /// Process 29 | /// 30 | /// 31 | /// 32 | public override void Process(TagHelperContext context, TagHelperOutput output) 33 | { 34 | output.Content.Clear(); 35 | var lengthMenu = CommonHelpers.GetGrid(context).LengthMenu; 36 | 37 | lengthMenu._lengthMenuValues = Values.ToList(); 38 | lengthMenu._lengthMenuDisplayedTexts = Values.Select(x => x.ToString()).ToList(); 39 | 40 | if (!lengthMenu._pageLength.HasValue) 41 | { 42 | lengthMenu._pageLength = lengthMenu._lengthMenuValues.FirstOrDefault(); 43 | } 44 | 45 | if (HasAll) 46 | { 47 | lengthMenu._lengthMenuValues.Add(-1); 48 | lengthMenu._lengthMenuDisplayedTexts.Add(AllText); 49 | } 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /DatatableJS/Helpers/OrdersHelper.cs: -------------------------------------------------------------------------------- 1 | using DatatableJS.Exceptions; 2 | using Microsoft.AspNetCore.Razor.TagHelpers; 3 | using System.Linq; 4 | 5 | namespace DatatableJS.Helpers 6 | { 7 | /// 8 | /// Enable ordering and set default orders. 9 | /// 10 | [HtmlTargetElement("orders", ParentTag = "js-datatable")] 11 | public class OrdersHelper : TagHelper 12 | { 13 | /// 14 | /// Process 15 | /// 16 | /// 17 | /// 18 | public override void Process(TagHelperContext context, TagHelperOutput output) 19 | { 20 | base.Process(context, output); 21 | } 22 | } 23 | 24 | /// 25 | /// Adds the specified property for default ordering. 26 | /// 27 | [HtmlTargetElement("add", ParentTag = "orders")] 28 | public class OrderHelper : TagHelper 29 | { 30 | public string Field { get; set; } 31 | public OrderBy OrderBy { get; set; } 32 | 33 | /// 34 | /// Process 35 | /// 36 | /// 37 | /// 38 | public override void Process(TagHelperContext context, TagHelperOutput output) 39 | { 40 | output.Content.Clear(); 41 | var grid = CommonHelpers.GetGrid(context); 42 | grid.Ordering = true; 43 | 44 | var column = grid.Columns.Where(c => c.Data.Equals(Field)).FirstOrDefault(); 45 | 46 | if (column == null) 47 | { 48 | throw new ColumnNotFoundException(string.Format("Column not found for property {0}", Field)); 49 | } 50 | 51 | var columnIndex = grid.Columns.IndexOf(column); 52 | 53 | grid.Orders.Add(new OrderModel 54 | { 55 | Field = Field, 56 | Column = columnIndex, 57 | OrderBy = OrderBy 58 | }); 59 | } 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /DatatableJS/Helpers/PaginateHelper.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Razor.TagHelpers; 2 | 3 | namespace DatatableJS.Helpers 4 | { 5 | /// 6 | /// Pagination specific language strings. 7 | /// 8 | [HtmlTargetElement("paginate", ParentTag = "language", TagStructure = TagStructure.WithoutEndTag)] 9 | public class PaginateHelper : TagHelper 10 | { 11 | /// 12 | /// Pagination 'First' button string. 13 | /// 14 | public string First { get; set; } 15 | 16 | /// 17 | /// Pagination 'Last' button string. 18 | /// 19 | public string Last { get; set; } 20 | 21 | /// 22 | /// Pagination 'Next' button string. 23 | /// 24 | public string Next { get; set; } 25 | 26 | /// 27 | /// Pagination 'Previous' button string. 28 | /// 29 | public string Previous { get; set; } 30 | 31 | /// 32 | /// Process 33 | /// 34 | /// 35 | /// 36 | public override void Process(TagHelperContext context, TagHelperOutput output) 37 | { 38 | output.Content.Clear(); 39 | var paginate = CommonHelpers.GetGrid(context).Language.Paginate; 40 | paginate.First = First; 41 | paginate.Last = Last; 42 | paginate.Next = Next; 43 | paginate.Previous = Previous; 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /DatatableJS/Helpers/RenderHelper.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Razor.TagHelpers; 2 | using Newtonsoft.Json; 3 | using System.Linq; 4 | 5 | namespace DatatableJS 6 | { 7 | /// 8 | /// Render datatable to create 9 | /// 10 | [HtmlTargetElement("render", ParentTag = "js-datatable", TagStructure = TagStructure.WithoutEndTag)] 11 | public class RenderHelper : TagHelper 12 | { 13 | /// 14 | /// Process 15 | /// 16 | /// 17 | /// 18 | public override void Process(TagHelperContext context, TagHelperOutput output) 19 | { 20 | output.TagName = "script"; 21 | output.TagMode = TagMode.StartTagAndEndTag; 22 | output.Content.Clear(); 23 | var grid = CommonHelpers.GetGrid(context); 24 | 25 | var lengthMenu = (grid.LengthMenu._lengthMenuValues.Count == 0) ? string.Empty : 26 | $"lengthMenu: {string.Format("[[{0}], [{1}]]", string.Join(", ", grid.LengthMenu._lengthMenuValues), string.Join(", ", grid.LengthMenu._lengthMenuDisplayedTexts.Select(a => string.Concat(@"""", a, @""""))))}," 27 | ; 28 | 29 | var colReorderInit = grid.ColReorder.Settings ? 30 | $@"colReorder: {{ 31 | enable: {grid.ColReorder.Enable.ToLowString()}, 32 | fixedColumnsLeft: {grid.ColReorder.FixedColumnsLeft}, 33 | fixedColumnsRight: {grid.ColReorder.FixedColumnsRight}, 34 | order: {grid.ColReorder.Order}, 35 | realtime: {grid.ColReorder.RealTime.ToLowString()} 36 | }}," 37 | : $"colReorder: {grid.ColReorder.ColReorder.ToLowString()},"; 38 | 39 | var script = $@" 40 | $(document).ready(function () {{ 41 | $('#{grid.Name}').DataTable( {{ 42 | processing: {grid.Processing.ToLowString()}, 43 | scrollX: {grid.ScrollX.ToLowString()}, 44 | stateSave: {grid.StateSave.ToLowString()}, 45 | serverSide: {grid.DataSource.ServerSide.ToLowString()}, 46 | {colReorderInit} 47 | fixedColumns: {{ 48 | leftColumns: {grid.FixedColumns?.LeftColumns}, 49 | rightColumns: {grid.FixedColumns?.RightColumns} 50 | }}, 51 | order: [{(!grid.Ordering ? string.Empty : string.Join(", ", grid.Orders.Select(a => $@"[{ a.Column}, '{(a.OrderBy == OrderBy.Ascending ? "asc" : "desc")}']")))}], 52 | ordering: {grid.Ordering.ToLowString()}, 53 | searching: {grid.Searching.ToLowString()}, 54 | paging: {grid.DataSource.Paging.ToLowString()}, 55 | {lengthMenu} 56 | {(!string.IsNullOrEmpty(grid.Callback.CreatedRow) ? $"createdRow: function (row, data, dataIndex, cells) {{ {grid.Callback.CreatedRow}(row, data, dataIndex, cells); }}," : string.Empty) } 57 | {(!string.IsNullOrEmpty(grid.Callback.DrawCallback) ? $"drawCallback: function (settings) {{ {grid.Callback.DrawCallback}(settings); }}," : string.Empty) } 58 | {(!string.IsNullOrEmpty(grid.Callback.FooterCallback) ? $"footerCallback: function (tfoot, data, start, end, display) {{ {grid.Callback.FooterCallback}(tfoot, data, start, end, display); }}," : string.Empty) } 59 | {(!string.IsNullOrEmpty(grid.Callback.FormatNumber) ? $"formatNumber: function (toFormat) {{ {grid.Callback.FormatNumber}(toFormat); }}," : string.Empty) } 60 | {(!string.IsNullOrEmpty(grid.Callback.HeaderCallback) ? $"headerCallback: function (thead, data, start, end, display) {{ {grid.Callback.HeaderCallback}(thead, data, start, end, display); }}," : string.Empty) } 61 | {(!string.IsNullOrEmpty(grid.Callback.InfoCallback) ? $"infoCallback: function (settings, start, end, max, total, pre) {{ {grid.Callback.InfoCallback}(settings, start, end, max, total, pre); }}," : string.Empty) } 62 | {(!string.IsNullOrEmpty(grid.Callback.InitComplete) ? $"initComplete: function (settings, json) {{ {grid.Callback.InitComplete}(settings, json); }}," : string.Empty) } 63 | {(!string.IsNullOrEmpty(grid.Callback.PreDrawCallback) ? $"preDrawCallback: function (settings) {{ {grid.Callback.PreDrawCallback}(settings); }}," : string.Empty) } 64 | {(!string.IsNullOrEmpty(grid.Callback.RowCallback) ? $"rowCallback: function (row, data, displayNum, displayIndex, dataIndex) {{ {grid.Callback.RowCallback}(row, data, displayNum, displayIndex, dataIndex); }}," : string.Empty) } 65 | {(!string.IsNullOrEmpty(grid.Callback.StateLoadCallback) ? $"stateLoadCallback: function (settings, callback) {{ {grid.Callback.StateLoadCallback}(settings, callback); }}," : string.Empty) } 66 | {(!string.IsNullOrEmpty(grid.Callback.StateLoadParams) ? $"stateLoadParams: function (settings, data) {{ {grid.Callback.StateLoadParams}(settings, data); }}," : string.Empty) } 67 | {(!string.IsNullOrEmpty(grid.Callback.StateLoaded) ? $"stateLoaded: function (settings, data) {{ {grid.Callback.StateLoaded}(settings, data); }}," : string.Empty) } 68 | {(!string.IsNullOrEmpty(grid.Callback.StateSaveCallback) ? $"stateSaveCallback: function (settings, data) {{ {grid.Callback.StateSaveCallback}(settings, data); }}," : string.Empty) } 69 | {(!string.IsNullOrEmpty(grid.Callback.StateSaveParams) ? $"stateSaveParams: function (settings, data) {{ {grid.Callback.StateSaveParams}(settings, data); }}," : string.Empty) } 70 | {(!grid.DataSource.PageLength.HasValue ? string.Empty : $"pageLength: {grid.DataSource.PageLength.Value},")} 71 | language: {{ 72 | url: '{grid.Language.URL}', 73 | {(!string.IsNullOrEmpty(grid.Language.Decimal) ? $"decimal: '{grid.Language.Decimal}'," : string.Empty)} 74 | {(!string.IsNullOrEmpty(grid.Language.EmptyTable) ? $"emptyTable: '{grid.Language.EmptyTable}'," : string.Empty)} 75 | {(!string.IsNullOrEmpty(grid.Language.Info) ? $"info: '{grid.Language.Info}'," : string.Empty)} 76 | {(!string.IsNullOrEmpty(grid.Language.InfoEmpty) ? $"infoEmpty: '{grid.Language.InfoEmpty}'," : string.Empty)} 77 | {(!string.IsNullOrEmpty(grid.Language.InfoFiltered) ? $"infoFiltered: '{grid.Language.InfoFiltered}'," : string.Empty)} 78 | {(!string.IsNullOrEmpty(grid.Language.InfoPostFix) ? $"infoPostFix: '{grid.Language.InfoPostFix}'," : string.Empty)} 79 | {(!string.IsNullOrEmpty(grid.Language.Thousands) ? $"thousands: '{grid.Language.Thousands}'," : string.Empty)} 80 | {(!string.IsNullOrEmpty(grid.Language.LengthMenu) ? $"lengthMenu: '{grid.Language.LengthMenu}'," : string.Empty)} 81 | {(!string.IsNullOrEmpty(grid.Language.LoadingRecords) ? $"loadingRecords: '{grid.Language.LoadingRecords}'," : string.Empty)} 82 | {(!string.IsNullOrEmpty(grid.Language.Processing) ? $"processing: '{grid.Language.Processing}'," : string.Empty)} 83 | {(!string.IsNullOrEmpty(grid.Language.Search) ? $"search: '{grid.Language.Search}'," : string.Empty)} 84 | {(!string.IsNullOrEmpty(grid.Language.ZeroRecords) ? $"zeroRecords: '{grid.Language.ZeroRecords}'," : string.Empty)} 85 | paginate: {{ 86 | {(!string.IsNullOrEmpty(grid.Language.Paginate.First) ? $"first: '{grid.Language.Paginate.First}'," : string.Empty)} 87 | {(!string.IsNullOrEmpty(grid.Language.Paginate.Last) ? $"last: '{grid.Language.Paginate.Last}'," : string.Empty)} 88 | {(!string.IsNullOrEmpty(grid.Language.Paginate.Next) ? $"next: '{grid.Language.Paginate.Next}'," : string.Empty)} 89 | {(!string.IsNullOrEmpty(grid.Language.Paginate.Previous) ? $"previous: '{grid.Language.Paginate.Previous}'," : string.Empty)} 90 | }}, 91 | aria: {{ 92 | {(!string.IsNullOrEmpty(grid.Language.Aria.SortAscending) ? $"sortAscending: '{grid.Language.Aria.SortAscending}'," : string.Empty)} 93 | {(!string.IsNullOrEmpty(grid.Language.Aria.SortDescending) ? $"sortDescending: '{grid.Language.Aria.SortDescending}'," : string.Empty)} 94 | }} 95 | }}, 96 | ajax: {{ 97 | url: ""{grid.DataSource.URL}"", 98 | type: ""{grid.DataSource.Method}"", 99 | data: {GetDataStr(grid)} 100 | }}, 101 | columns: [{string.Join(", ", grid.Columns.Select(a => $@"{{ 102 | data: '{(grid.DataSource.CamelCase ? char.ToLowerInvariant(a.Data[0]) + a.Data.Substring(1) : a.Data)}', 103 | name: '{a.Data}', 104 | defaultContent: '{a.DefaultContent}', 105 | orderable: {a.Orderable.ToLowString()}, 106 | searchable: {a.Searchable.ToLowString()}, 107 | className: '{a.ClassName}', 108 | visible: {a.Visible.ToLowString()}, 109 | width: '{a.Width}%', 110 | {(string.IsNullOrEmpty(a.Render) ? string.Empty : $"'render': function(data, type, row, meta) {{ return {a.Render}; }}")} 111 | }}"))}] 112 | }}); 113 | }}); 114 | {(string.IsNullOrEmpty(grid.Captions.Top) ? string.Empty : string.Format("$('#{0}').append('{1}');", grid.Name, grid.Captions.Top))} 115 | {(string.IsNullOrEmpty(grid.Captions.Bottom) ? string.Empty : string.Format("$('#{0}').append('{1}');", grid.Name, grid.Captions.Bottom))}"; 116 | 117 | output.Content.AppendHtml(script); 118 | } 119 | 120 | private string GetDataStr(GridModel grid) 121 | { 122 | var filters = string.Format("d.filters = {0}{1}", JsonConvert.SerializeObject(grid.Filters), string.IsNullOrEmpty(grid.DataSource.Data) ? string.Empty : ","); 123 | 124 | return $@"function (d) {{ 125 | {(grid.Filters.Count > 0 ? filters : string.Empty)} 126 | {(string.IsNullOrEmpty(grid.DataSource.Data) ? string.Empty : string.Format("d.data = {0}()", grid.DataSource.Data))} 127 | }}"; 128 | } 129 | } 130 | } 131 | -------------------------------------------------------------------------------- /DatatableJS/Models/CallbackModel.cs: -------------------------------------------------------------------------------- 1 | namespace DatatableJS 2 | { 3 | public class CallbackModel 4 | { 5 | public string CreatedRow { get; set; } 6 | public string DrawCallback { get; set; } 7 | public string FooterCallback { get; set; } 8 | public string FormatNumber { get; set; } 9 | public string HeaderCallback { get; set; } 10 | public string InfoCallback { get; set; } 11 | public string InitComplete { get; set; } 12 | public string PreDrawCallback { get; set; } 13 | public string RowCallback { get; set; } 14 | public string StateLoadCallback { get; set; } 15 | public string StateLoadParams { get; set; } 16 | public string StateLoaded { get; set; } 17 | public string StateSaveCallback { get; set; } 18 | public string StateSaveParams { get; set; } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /DatatableJS/Models/CaptionsModel.cs: -------------------------------------------------------------------------------- 1 | namespace DatatableJS 2 | { 3 | public class CaptionsModel 4 | { 5 | public string Top { get; set; } 6 | public string Bottom { get; set; } 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /DatatableJS/Models/ColReorderModel.cs: -------------------------------------------------------------------------------- 1 | namespace DatatableJS 2 | { 3 | class ColReorderModel 4 | { 5 | public bool ColReorder { get; set; } 6 | public bool Settings { get; set; } 7 | public bool Enable { get; set; } = true; 8 | public int FixedColumnsLeft { get; set; } 9 | public int FixedColumnsRight { get; set; } 10 | public string Order { get; set; } = "null"; 11 | public bool RealTime { get; set; } = true; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /DatatableJS/Models/ColumnModel.cs: -------------------------------------------------------------------------------- 1 | namespace DatatableJS 2 | { 3 | public class ColumnModel 4 | { 5 | public string Data { get; set; } 6 | public bool Visible { get; set; } 7 | public bool Searchable { get; set; } 8 | public bool Orderable { get; set; } 9 | public int Width { get; set; } 10 | public string ClassName { get; set; } 11 | public string DefaultContent { get; set; } 12 | public string Render { get; set; } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /DatatableJS/Models/Command.cs: -------------------------------------------------------------------------------- 1 | namespace DatatableJS 2 | { 3 | public class Command 4 | { 5 | public string Text { get; private set; } 6 | public string OnClick { get; private set; } 7 | public Command(string text, string onClick) 8 | { 9 | Text = text; 10 | OnClick = onClick; 11 | } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /DatatableJS/Models/DataSourceModel.cs: -------------------------------------------------------------------------------- 1 | namespace DatatableJS 2 | { 3 | /// 4 | /// DataSourceModel 5 | /// 6 | public class DataSourceModel 7 | { 8 | internal string URL { get; set; } 9 | internal HttpMethodType Method { get; set; } 10 | internal bool CamelCase { get; set; } 11 | internal bool Paging { get; set; } 12 | internal string Data { get; set; } 13 | internal bool ServerSide { get; set; } 14 | internal int? PageLength { get; set; } 15 | } 16 | 17 | /// 18 | /// HttpMethodType 19 | /// 20 | public enum HttpMethodType 21 | { 22 | /// 23 | /// GET 24 | /// 25 | GET, 26 | /// 27 | /// POST 28 | /// 29 | POST 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /DatatableJS/Models/Enums.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel; 2 | 3 | namespace DatatableJS 4 | { 5 | /// 6 | /// Set which items are selectable (row, column, cell, row with checkbox). Default is row. 7 | /// 8 | public enum SelectItems 9 | { 10 | /// 11 | /// Enable row selection. 12 | /// 13 | [Description("row")] 14 | Row, 15 | 16 | /// 17 | /// Enable column selection. 18 | /// 19 | [Description("column")] 20 | Column, 21 | 22 | /// 23 | /// Enable cell selection. 24 | /// 25 | [Description("cell")] 26 | Cell, 27 | 28 | /// 29 | /// Enable row selection with checkbox. 30 | /// 31 | [Description("row")] 32 | Checkbox 33 | } 34 | 35 | /// 36 | /// Set select style functionalities. 37 | /// 38 | public enum SelectStyle 39 | { 40 | /// 41 | /// Select just for single item, to select multiple just click with CTRL button. 42 | /// 43 | [Description("os")] 44 | Default, 45 | 46 | /// 47 | /// Only single item can be selected. 48 | /// 49 | [Description("single")] 50 | Single, 51 | 52 | /// 53 | /// Multiple selectable with one click 54 | /// 55 | [Description("multi")] 56 | Multi, 57 | 58 | /// 59 | /// Multi-item with rangle selection 60 | /// 61 | [Description("multi+shift")] 62 | MultiShift 63 | } 64 | 65 | /// 66 | /// Select position of the column search box 67 | /// 68 | public enum SearchPosition 69 | { 70 | /// 71 | /// Footer 72 | /// 73 | Footer, 74 | 75 | /// 76 | /// Header 77 | /// 78 | Header 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /DatatableJS/Models/FilterModel.cs: -------------------------------------------------------------------------------- 1 | namespace DatatableJS 2 | { 3 | public class FilterModel 4 | { 5 | public string Field { get; set; } 6 | public string Value { get; set; } 7 | public Operand Operand { get; set; } 8 | } 9 | 10 | public enum Operand 11 | { 12 | Equal, 13 | NotEqual, 14 | GreaterThan, 15 | LessThan, 16 | GreaterThanOrEqual, 17 | LessThanOrEqual, 18 | Contains, 19 | StartsWith, 20 | EndsWith 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /DatatableJS/Models/FixedColumnsModel.cs: -------------------------------------------------------------------------------- 1 | namespace DatatableJS 2 | { 3 | public class FixedColumnsModel 4 | { 5 | public int LeftColumns { get; set; } 6 | public int RightColumns { get; set; } 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /DatatableJS/Models/GridModel.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace DatatableJS 4 | { 5 | /// 6 | /// GridModel 7 | /// 8 | public class GridModel 9 | { 10 | internal string Name { get; set; } 11 | internal bool Ordering { get; set; } 12 | internal bool Searching { get; set; } 13 | internal bool Processing { get; set; } 14 | internal bool ScrollX { get; set; } 15 | internal bool StateSave { get; set; } 16 | 17 | internal string Dom { get; set; } 18 | 19 | internal List Columns { get; set; } 20 | internal List Filters { get; set; } 21 | internal List Orders { get; set; } 22 | 23 | internal DataSourceModel DataSource { get; set; } 24 | internal FixedColumnsModel FixedColumns { get; set; } 25 | internal LanguageModel Language { get; set; } 26 | internal CaptionsModel Captions { get; set; } 27 | internal LengthMenuModel LengthMenu { get; set; } 28 | internal CallbackModel Callback { get; set; } 29 | internal ColReorderModel ColReorder { get; set; } 30 | 31 | /// 32 | /// GridModel() 33 | /// 34 | public GridModel() 35 | { 36 | Columns = new List(); 37 | Filters = new List(); 38 | DataSource = new DataSourceModel(); 39 | FixedColumns = new FixedColumnsModel(); 40 | Language = new LanguageModel(); 41 | Captions = new CaptionsModel(); 42 | Orders = new List(); 43 | LengthMenu = new LengthMenuModel(); 44 | Callback = new CallbackModel(); 45 | ColReorder = new ColReorderModel(); 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /DatatableJS/Models/LanguageModel.cs: -------------------------------------------------------------------------------- 1 | namespace DatatableJS 2 | { 3 | internal class LanguageModel 4 | { 5 | internal string URL { get; set; } 6 | internal string Decimal { get; set; } 7 | internal string EmptyTable { get; set; } 8 | internal string Info { get; set; } 9 | internal string InfoEmpty { get; set; } 10 | internal string InfoFiltered { get; set; } 11 | internal string InfoPostFix { get; set; } 12 | internal string Thousands { get; set; } 13 | internal string LengthMenu { get; set; } 14 | internal string LoadingRecords { get; set; } 15 | internal string Processing { get; set; } 16 | internal string Search { get; set; } 17 | internal string ZeroRecords { get; set; } 18 | internal PaginateModel Paginate { get; set; } = new PaginateModel(); 19 | internal AriaModel Aria { get; set; } = new AriaModel(); 20 | } 21 | 22 | internal class PaginateModel 23 | { 24 | public string First { get; set; } 25 | public string Last { get; set; } 26 | public string Next { get; set; } 27 | public string Previous { get; set; } 28 | } 29 | 30 | internal class AriaModel 31 | { 32 | public string SortAscending { get; set; } 33 | public string SortDescending { get; set; } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /DatatableJS/Models/LengthMenuModel.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace DatatableJS 4 | { 5 | public class LengthMenuModel 6 | { 7 | internal List _lengthMenuValues { get; set; } = new List(); 8 | internal List _lengthMenuDisplayedTexts { get; set; } = new List(); 9 | internal int? _pageLength { get; set; } 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /DatatableJS/Models/OrderModel.cs: -------------------------------------------------------------------------------- 1 | namespace DatatableJS 2 | { 3 | #pragma warning disable CS1591 // Missing XML comment for publicly visible type or member 4 | public class OrderModel 5 | { 6 | public string Field { get; set; } 7 | public int Column { get; set; } 8 | public OrderBy OrderBy { get; set; } 9 | } 10 | 11 | public enum OrderBy 12 | { 13 | Ascending, 14 | Descending 15 | } 16 | } -------------------------------------------------------------------------------- /DatatableJS/Utilities/ExpressionHelpers.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq.Expressions; 3 | 4 | namespace DatatableJS 5 | { 6 | internal static class ExpressionHelpers 7 | { 8 | public static string PropertyName(Expression> expression) 9 | { 10 | var body = expression.Body as MemberExpression; 11 | 12 | if (body == null) 13 | { 14 | body = ((UnaryExpression)expression.Body).Operand as MemberExpression; 15 | } 16 | 17 | return body.Member.Name; 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Emrah KONDUR 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | > DatatableJs will **no longer** be maintained. For a more advanced version, visit [RazorKit](https://github.com/ekondur/RazorKit) 2 | -------------------------------------------------------------------------------- /_config.yml: -------------------------------------------------------------------------------- 1 | theme: jekyll-theme-architect -------------------------------------------------------------------------------- /appveyor.yml: -------------------------------------------------------------------------------- 1 | version: 1.0.{build} 2 | before_build: 3 | - nuget restore 4 | -------------------------------------------------------------------------------- /datatable-js.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ekondur/DatatableJS/456a55f1cdd87fe2556a45610c935b6308bfe934/datatable-js.png --------------------------------------------------------------------------------