├── src ├── Freelancer.OrchardCore │ ├── Views │ │ ├── HtmlField.liquid │ │ ├── Widget.liquid │ │ ├── Widget.Wrapper.liquid │ │ ├── MenuItem.liquid │ │ ├── MenuItemLink-LinkMenuItem.liquid │ │ ├── Menu.liquid │ │ └── Layout.liquid │ ├── Recipes │ │ ├── Snippets │ │ │ ├── Copyright.html │ │ │ ├── Footer.html │ │ │ ├── About.html │ │ │ ├── Contact.html │ │ │ └── LandingPage.liquid │ │ └── freelancer.recipe.json │ ├── wwwroot │ │ ├── Theme.png │ │ ├── img │ │ │ ├── favicon.ico │ │ │ ├── portfolio │ │ │ │ ├── cake.png │ │ │ │ ├── game.png │ │ │ │ ├── safe.png │ │ │ │ ├── cabin.png │ │ │ │ ├── circus.png │ │ │ │ └── submarine.png │ │ │ └── profiles │ │ │ │ └── avataaars.svg │ │ └── js │ │ │ ├── scripts.js │ │ │ ├── contact_me.js │ │ │ └── jqBootstrapValidation.js │ ├── Manifest.cs │ └── Freelancer.OrchardCore.csproj ├── Directory.Build.props └── Common.props ├── assets ├── freelancer-recipe.png ├── orchard-core-cms-theme-freelancer.png └── orchard-core-cms-theme-landing-page.png ├── NuGet.config ├── appveyor.yml ├── LICENSE ├── README.md ├── Freelancer.sln └── .gitignore /src/Freelancer.OrchardCore/Views/HtmlField.liquid: -------------------------------------------------------------------------------- 1 | {{ Model.Html | raw }} -------------------------------------------------------------------------------- /src/Freelancer.OrchardCore/Views/Widget.liquid: -------------------------------------------------------------------------------- 1 | {{ Model.Content | shape_render }} -------------------------------------------------------------------------------- /src/Freelancer.OrchardCore/Views/Widget.Wrapper.liquid: -------------------------------------------------------------------------------- 1 | {{ Model.Content | shape_render }} 2 | -------------------------------------------------------------------------------- /src/Freelancer.OrchardCore/Recipes/Snippets/Copyright.html: -------------------------------------------------------------------------------- 1 | Copyright © Your Website 2020 -------------------------------------------------------------------------------- /assets/freelancer-recipe.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidhayden/Freelancer/HEAD/assets/freelancer-recipe.png -------------------------------------------------------------------------------- /assets/orchard-core-cms-theme-freelancer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidhayden/Freelancer/HEAD/assets/orchard-core-cms-theme-freelancer.png -------------------------------------------------------------------------------- /src/Freelancer.OrchardCore/wwwroot/Theme.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidhayden/Freelancer/HEAD/src/Freelancer.OrchardCore/wwwroot/Theme.png -------------------------------------------------------------------------------- /assets/orchard-core-cms-theme-landing-page.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidhayden/Freelancer/HEAD/assets/orchard-core-cms-theme-landing-page.png -------------------------------------------------------------------------------- /src/Freelancer.OrchardCore/wwwroot/img/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidhayden/Freelancer/HEAD/src/Freelancer.OrchardCore/wwwroot/img/favicon.ico -------------------------------------------------------------------------------- /src/Freelancer.OrchardCore/wwwroot/img/portfolio/cake.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidhayden/Freelancer/HEAD/src/Freelancer.OrchardCore/wwwroot/img/portfolio/cake.png -------------------------------------------------------------------------------- /src/Freelancer.OrchardCore/wwwroot/img/portfolio/game.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidhayden/Freelancer/HEAD/src/Freelancer.OrchardCore/wwwroot/img/portfolio/game.png -------------------------------------------------------------------------------- /src/Freelancer.OrchardCore/wwwroot/img/portfolio/safe.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidhayden/Freelancer/HEAD/src/Freelancer.OrchardCore/wwwroot/img/portfolio/safe.png -------------------------------------------------------------------------------- /src/Freelancer.OrchardCore/wwwroot/img/portfolio/cabin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidhayden/Freelancer/HEAD/src/Freelancer.OrchardCore/wwwroot/img/portfolio/cabin.png -------------------------------------------------------------------------------- /src/Freelancer.OrchardCore/wwwroot/img/portfolio/circus.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidhayden/Freelancer/HEAD/src/Freelancer.OrchardCore/wwwroot/img/portfolio/circus.png -------------------------------------------------------------------------------- /src/Freelancer.OrchardCore/wwwroot/img/portfolio/submarine.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidhayden/Freelancer/HEAD/src/Freelancer.OrchardCore/wwwroot/img/portfolio/submarine.png -------------------------------------------------------------------------------- /src/Freelancer.OrchardCore/Views/MenuItem.liquid: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/Freelancer.OrchardCore/Views/MenuItemLink-LinkMenuItem.liquid: -------------------------------------------------------------------------------- 1 | {% assign link = Model.ContentItem.Content.LinkMenuItemPart %} 2 | {{ link.Name }} -------------------------------------------------------------------------------- /src/Freelancer.OrchardCore/Views/Menu.liquid: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/Freelancer.OrchardCore/Manifest.cs: -------------------------------------------------------------------------------- 1 | using OrchardCore.DisplayManagement.Manifest; 2 | 3 | [assembly: Theme( 4 | Name = "Freelancer", 5 | Author = "David Hayden", 6 | Website = "https://www.davidhayden.me", 7 | Version = "1.0.0-rc2", 8 | Description = "One page Bootstrap portfolio theme for freelancers based on Start Bootstrap template.", 9 | Tags = new[] { "Bootstrap", "Freelancer", "Liquid" } 10 | )] 11 | -------------------------------------------------------------------------------- /NuGet.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /src/Freelancer.OrchardCore/Freelancer.OrchardCore.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netcoreapp3.1 5 | true 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /src/Directory.Build.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Freelancer.OrchardCore 5 | Freelancer Theme for Orchard Core 6 | One page Bootstrap portfolio theme for freelancers based on Start Bootstrap template. 7 | Freelancer;OrchardCore 8 | 1.0.0 9 | rc2 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /appveyor.yml: -------------------------------------------------------------------------------- 1 | skip_commits: 2 | files: 3 | - assets/* 4 | - NuGet.config 5 | - README.md 6 | 7 | image: Visual Studio 2019 8 | init: 9 | - git config --global core.autocrlf true 10 | install: 11 | - ps: $env:BuildNumber= $env:APPVEYOR_BUILD_NUMBER 12 | - ps: $env:DOTNET_SKIP_FIRST_TIME_EXPERIENCE = true 13 | - ps: $env:NUGET_XMLDOC_MODE = "skip" 14 | - ps: $env:DOTNET_CLI_TELEMETRY_OPTOUT = 1 15 | build_script: 16 | - dotnet --version 17 | - dotnet restore 18 | - dotnet build -c Release 19 | - dotnet pack -c Release 20 | artifacts: 21 | - path: 'src\**\*.nupkg' 22 | deploy: 23 | - provider: NuGet 24 | on: 25 | branch: master 26 | server: https://www.myget.org/F/davidhayden-ci/api/v2/package 27 | api_key: 28 | secure: zO9VvXdyZxlJe4oXgfO5NBtulXZUZ5YWLvI+YoKn0TFW7mq7hL/GZuxt1O2t7D7K 29 | skip_symbols: true 30 | artifact: /.*\.nupkg/ -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 David Hayden 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 | -------------------------------------------------------------------------------- /src/Freelancer.OrchardCore/Recipes/Snippets/Footer.html: -------------------------------------------------------------------------------- 1 |
2 | 3 |
4 |

Location

5 |

6 | 2215 John Daniel Drive 7 |
8 | Clark, MO 65243 9 |

10 |
11 | 12 |
13 |

Around the Web

14 | 15 | 16 | 17 | 18 |
19 | 20 |
21 |

About Freelancer

22 |

23 | Freelance is a free to use, MIT licensed Bootstrap theme created by 24 | Start Bootstrap 25 | . 26 |

27 |
28 |
-------------------------------------------------------------------------------- /src/Common.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | David Hayden 5 | David Hayden 6 | https://github.com/davidhayden/Freelancer 7 | https://github.com/davidhayden/Freelancer 8 | https://github.com/davidhayden/Freelancer/blob/master/LICENSE 9 | netcoreapp3.1 10 | $(VersionSuffix)-$(BuildNumber) 11 | true 12 | embedded 13 | true 14 | false 15 | false 16 | false 17 | false 18 | false 19 | false 20 | false 21 | false 22 | 23 | 24 | -------------------------------------------------------------------------------- /src/Freelancer.OrchardCore/Recipes/Snippets/About.html: -------------------------------------------------------------------------------- 1 |
2 |
3 | 4 |

About

5 | 6 |
7 |
8 |
9 |
10 |
11 | 12 |
13 |

Freelancer is a free bootstrap theme created by Start Bootstrap. The theme is customized to work with Orchard Core CMS by David Hayden. View source on GitHub.

14 |

You can create your own custom avatar for the masthead, change the icon in the dividers, and add your email address to the contact form to make it fully functional!

15 |
16 | 17 | 23 |
24 |
-------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Freelancer 2 | 3 | Custom theme for Orchard Core CMS based on the one page portfolio [Freelancer Start Bootstrap](https://startbootstrap.com/template-overviews/freelancer/) HTML template. The theme includes a custom Setup Recipe that creates a working landing page with a portfolio, about and contact sections. 4 | 5 | ## Status 6 | 7 | [![Build status](https://ci.appveyor.com/api/projects/status/wc8dydpub9cnr72d?svg=true)](https://ci.appveyor.com/project/davidhayden/freelancer) [![Status](https://img.shields.io/myget/davidhayden-ci/v/Freelancer.OrchardCore.svg)](https://www.myget.org/feed/davidhayden-ci/package/nuget/Freelancer.OrchardCore) 8 | 9 | ## Change Log 10 | 11 | - 2020-07-28 Update to Freelancer v6.0.4 on Startbootstrap 12 | - 2020-06-23 Update to Orchard Core CMS 1.0.0-rc2 13 | - 2019-08-10 Update to Orchard Core CMS 1.0.0-beta3 14 | - 2018-08-31 Initial Release 15 | 16 | ## Getting Started 17 | 18 | Add the NuGet package, **Freelancer.OrchardCore**, to the Orchard Core CMS Website. Launch the application and choose the _Freelancer_ Recipe from the Setup Page. 19 | 20 | ![Freelancer Recipe for Orchard Core CMS](https://github.com/davidhayden/Freelancer/blob/master/assets/freelancer-recipe.png?raw=true) 21 | 22 | Complete the information and choose _Finish Setup_ to create the website. The landing page should appear. Sign in as an administrator and modify as necessary. 23 | 24 | ![Freelancer Preview](https://github.com/davidhayden/Freelancer/blob/master/assets/orchard-core-cms-theme-landing-page.png?raw=true) 25 | 26 | When you review the active themes for the website you will see Freelancer as the default theme. 27 | 28 | ![Freelancer Theme for Orchard Core CMS](https://github.com/davidhayden/Freelancer/blob/master/assets/orchard-core-cms-theme-freelancer.png?raw=true) 29 | 30 | ## Road map 31 | 32 | There are no plans to add any additional features to the code. 33 | 34 | ## Credits 35 | 36 | Theme created and maintained by David Hayden. 37 | 38 | Aside from minor changes, the theme is based on the [Freelancer Start Bootstrap HTML Template](https://startbootstrap.com/template-overviews/freelancer/). 39 | -------------------------------------------------------------------------------- /Freelancer.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 15 4 | VisualStudioVersion = 15.0.26124.0 5 | MinimumVisualStudioVersion = 15.0.26124.0 6 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{E905B4B9-3D19-477E-994C-8FCC8B84B4E2}" 7 | EndProject 8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Freelancer.OrchardCore", "src\Freelancer.OrchardCore\Freelancer.OrchardCore.csproj", "{390B4539-0176-41B4-97F4-1A55F954110E}" 9 | EndProject 10 | Global 11 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 12 | Debug|Any CPU = Debug|Any CPU 13 | Debug|x64 = Debug|x64 14 | Debug|x86 = Debug|x86 15 | Release|Any CPU = Release|Any CPU 16 | Release|x64 = Release|x64 17 | Release|x86 = Release|x86 18 | EndGlobalSection 19 | GlobalSection(SolutionProperties) = preSolution 20 | HideSolutionNode = FALSE 21 | EndGlobalSection 22 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 23 | {390B4539-0176-41B4-97F4-1A55F954110E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 24 | {390B4539-0176-41B4-97F4-1A55F954110E}.Debug|Any CPU.Build.0 = Debug|Any CPU 25 | {390B4539-0176-41B4-97F4-1A55F954110E}.Debug|x64.ActiveCfg = Debug|Any CPU 26 | {390B4539-0176-41B4-97F4-1A55F954110E}.Debug|x64.Build.0 = Debug|Any CPU 27 | {390B4539-0176-41B4-97F4-1A55F954110E}.Debug|x86.ActiveCfg = Debug|Any CPU 28 | {390B4539-0176-41B4-97F4-1A55F954110E}.Debug|x86.Build.0 = Debug|Any CPU 29 | {390B4539-0176-41B4-97F4-1A55F954110E}.Release|Any CPU.ActiveCfg = Release|Any CPU 30 | {390B4539-0176-41B4-97F4-1A55F954110E}.Release|Any CPU.Build.0 = Release|Any CPU 31 | {390B4539-0176-41B4-97F4-1A55F954110E}.Release|x64.ActiveCfg = Release|Any CPU 32 | {390B4539-0176-41B4-97F4-1A55F954110E}.Release|x64.Build.0 = Release|Any CPU 33 | {390B4539-0176-41B4-97F4-1A55F954110E}.Release|x86.ActiveCfg = Release|Any CPU 34 | {390B4539-0176-41B4-97F4-1A55F954110E}.Release|x86.Build.0 = Release|Any CPU 35 | EndGlobalSection 36 | GlobalSection(NestedProjects) = preSolution 37 | {390B4539-0176-41B4-97F4-1A55F954110E} = {E905B4B9-3D19-477E-994C-8FCC8B84B4E2} 38 | EndGlobalSection 39 | EndGlobal 40 | -------------------------------------------------------------------------------- /src/Freelancer.OrchardCore/wwwroot/js/scripts.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * Start Bootstrap - Freelancer v6.0.4 (https://startbootstrap.com/themes/freelancer) 3 | * Copyright 2013-2020 Start Bootstrap 4 | * Licensed under MIT (https://github.com/StartBootstrap/startbootstrap-freelancer/blob/master/LICENSE) 5 | */ 6 | (function($) { 7 | "use strict"; // Start of use strict 8 | 9 | // Smooth scrolling using jQuery easing 10 | $('a.js-scroll-trigger[href*="#"]:not([href="#"])').click(function() { 11 | if (location.pathname.replace(/^\//, '') == this.pathname.replace(/^\//, '') && location.hostname == this.hostname) { 12 | var target = $(this.hash); 13 | target = target.length ? target : $('[name=' + this.hash.slice(1) + ']'); 14 | if (target.length) { 15 | $('html, body').animate({ 16 | scrollTop: (target.offset().top - 71) 17 | }, 1000, "easeInOutExpo"); 18 | return false; 19 | } 20 | } 21 | }); 22 | 23 | // Scroll to top button appear 24 | $(document).scroll(function() { 25 | var scrollDistance = $(this).scrollTop(); 26 | if (scrollDistance > 100) { 27 | $('.scroll-to-top').fadeIn(); 28 | } else { 29 | $('.scroll-to-top').fadeOut(); 30 | } 31 | }); 32 | 33 | // Closes responsive menu when a scroll trigger link is clicked 34 | $('.js-scroll-trigger').click(function() { 35 | $('.navbar-collapse').collapse('hide'); 36 | }); 37 | 38 | // Activate scrollspy to add active class to navbar items on scroll 39 | $('body').scrollspy({ 40 | target: '#mainNav', 41 | offset: 80 42 | }); 43 | 44 | // Collapse Navbar 45 | var navbarCollapse = function() { 46 | if ($("#mainNav").offset().top > 100) { 47 | $("#mainNav").addClass("navbar-shrink"); 48 | } else { 49 | $("#mainNav").removeClass("navbar-shrink"); 50 | } 51 | }; 52 | // Collapse now if page is not at top 53 | navbarCollapse(); 54 | // Collapse the navbar when page is scrolled 55 | $(window).scroll(navbarCollapse); 56 | 57 | // Floating label headings for the contact form 58 | $(function() { 59 | $("body").on("input propertychange", ".floating-label-form-group", function(e) { 60 | $(this).toggleClass("floating-label-form-group-with-value", !!$(e.target).val()); 61 | }).on("focus", ".floating-label-form-group", function() { 62 | $(this).addClass("floating-label-form-group-with-focus"); 63 | }).on("blur", ".floating-label-form-group", function() { 64 | $(this).removeClass("floating-label-form-group-with-focus"); 65 | }); 66 | }); 67 | 68 | })(jQuery); // End of use strict 69 | -------------------------------------------------------------------------------- /src/Freelancer.OrchardCore/Recipes/Snippets/Contact.html: -------------------------------------------------------------------------------- 1 |
2 |
3 | 4 |

Contact Me

5 | 6 |
7 |
8 |
9 |
10 |
11 | 12 |
13 |
14 | 15 |
16 |
17 |
18 | 19 | 20 |

21 |
22 |
23 |
24 |
25 | 26 | 27 |

28 |
29 |
30 |
31 |
32 | 33 | 34 |

35 |
36 |
37 |
38 |
39 | 40 | 41 |

42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
-------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | 4 | # User-specific files 5 | *.suo 6 | *.user 7 | *.sln.docstates 8 | *.sln.ide/ 9 | 10 | # Build results 11 | 12 | [Dd]ebug/ 13 | [Rr]elease/ 14 | x64/ 15 | build/ 16 | app.publish/ 17 | [Bb]in/ 18 | [Oo]bj/ 19 | 20 | # Enable "build/" folder in the NuGet Packages folder since NuGet packages use it for MSBuild targets 21 | !packages/*/build/ 22 | 23 | # MSTest test Results 24 | [Tt]est[Rr]esult*/ 25 | [Bb]uild[Ll]og.* 26 | 27 | *_i.c 28 | *_p.c 29 | *.ilk 30 | *.meta 31 | *.obj 32 | *.pch 33 | *.pdb 34 | *.pgc 35 | *.pgd 36 | *.rsp 37 | *.sbr 38 | *.tlb 39 | *.tli 40 | *.tlh 41 | *.tmp 42 | *.tmp_proj 43 | *.log 44 | *.vspscc 45 | *.vssscc 46 | .builds 47 | *.pidb 48 | *.log 49 | *.scc 50 | project.lock.json 51 | 52 | # Visual C++ cache files 53 | ipch/ 54 | *.aps 55 | *.ncb 56 | *.opensdf 57 | *.sdf 58 | *.cachefile 59 | 60 | # Visual Studio profiler 61 | *.psess 62 | *.vsp 63 | *.vspx 64 | 65 | # Guidance Automation Toolkit 66 | *.gpState 67 | 68 | # ReSharper is a .NET coding add-in 69 | _ReSharper*/ 70 | *.[Rr]e[Ss]harper 71 | 72 | # TeamCity is a build add-in 73 | _TeamCity* 74 | 75 | # DotCover is a Code Coverage Tool 76 | *.dotCover 77 | 78 | # NCrunch 79 | *.ncrunch* 80 | .*crunch*.local.xml 81 | 82 | # Installshield output folder 83 | [Ee]xpress/ 84 | 85 | # DocProject is a documentation generator add-in 86 | DocProject/buildhelp/ 87 | DocProject/Help/*.HxT 88 | DocProject/Help/*.HxC 89 | DocProject/Help/*.hhc 90 | DocProject/Help/*.hhk 91 | DocProject/Help/*.hhp 92 | DocProject/Help/Html2 93 | DocProject/Help/html 94 | 95 | # Click-Once directory 96 | publish/ 97 | 98 | # Publish Web Output 99 | *.Publish.xml 100 | *.pubxml 101 | 102 | # NuGet Packages Directory 103 | ## TODO: If you have NuGet Package Restore enabled, uncomment the next line 104 | packages/ 105 | 106 | # Windows Azure Build Output 107 | csx 108 | *.build.csdef 109 | 110 | # Windows Store app package directory 111 | AppPackages/ 112 | 113 | # Others 114 | *.Cache 115 | !OrchardCore.Environment.Cache 116 | ClientBin/ 117 | [Ss]tyle[Cc]op.* 118 | ~$* 119 | *~ 120 | *.dbmdl 121 | *.[Pp]ublish.xml 122 | *.pfx 123 | *.publishsettings 124 | 125 | # RIA/Silverlight projects 126 | Generated_Code/ 127 | 128 | # Backup & report files from converting an old project file to a newer 129 | # Visual Studio version. Backup files are not needed, because we have git ;-) 130 | _UpgradeReport_Files/ 131 | Backup*/ 132 | UpgradeLog*.XML 133 | UpgradeLog*.htm 134 | 135 | # SQL Server files 136 | App_Data/*.mdf 137 | App_Data/*.ldf 138 | 139 | # ========================= 140 | # Windows detritus 141 | # ========================= 142 | 143 | # Windows image file caches 144 | Thumbs.db 145 | ehthumbs.db 146 | 147 | # Folder config file 148 | Desktop.ini 149 | 150 | # Recycle Bin used on file shares 151 | $RECYCLE.BIN/ 152 | 153 | # Mac crap 154 | .DS_Store 155 | 156 | # ========================= 157 | # Orchard specifics 158 | # ========================= 159 | 160 | App_Data/ 161 | glob:*.user 162 | *.patch 163 | *.hg 164 | build/ 165 | /buildazure 166 | /buildtasks 167 | /artifacts 168 | site/ 169 | *.sln.cache 170 | src/OrchardCore.Modules/**/launchSettings.json 171 | src/OrchardCore.Themes/**/launchSettings.json 172 | log.xml 173 | profiling/ 174 | *.orig 175 | .vs/ 176 | .vscode/ 177 | .build/ 178 | .testPublish/ 179 | .idea/ 180 | 181 | nuget.exe 182 | .nuget/ 183 | 184 | #enable all /lib artifacts 185 | !lib/*/*.* 186 | 187 | #exclude node modules 188 | node_modules/ 189 | -------------------------------------------------------------------------------- /src/Freelancer.OrchardCore/Views/Layout.liquid: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | {% render_section "HeadMeta", required: false %} 7 | {% page_title Site.SiteName, position: "before", separator: " - " %} 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | {% resources type: "Meta" %} 18 | {% resources type: "HeadLink" %} 19 | {% resources type: "Stylesheet" %} 20 | {% resources type: "HeadScript" %} 21 | 22 | 23 | 33 | {% if Request.Path != '/' %} 34 |
35 |
36 | {% render_section "Content", required: false %} 37 |
38 |
39 | {% else %} 40 | {% render_section "Content", required: false %} 41 | {% endif %} 42 | 47 | 52 |
53 | 54 | 55 | 56 |
57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | {% resources type: "FootScript" %} 67 | 68 | -------------------------------------------------------------------------------- /src/Freelancer.OrchardCore/wwwroot/js/contact_me.js: -------------------------------------------------------------------------------- 1 | $(function () { 2 | $( 3 | "#contactForm input,#contactForm textarea,#contactForm button" 4 | ).jqBootstrapValidation({ 5 | preventSubmit: true, 6 | submitError: function ($form, event, errors) { 7 | // additional error messages or events 8 | }, 9 | submitSuccess: function ($form, event) { 10 | event.preventDefault(); // prevent default submit behaviour 11 | // get values from FORM 12 | var name = $("input#name").val(); 13 | var email = $("input#email").val(); 14 | var phone = $("input#phone").val(); 15 | var message = $("textarea#message").val(); 16 | var firstName = name; // For Success/Failure Message 17 | // Check for white space in name for Success/Fail message 18 | if (firstName.indexOf(" ") >= 0) { 19 | firstName = name.split(" ").slice(0, -1).join(" "); 20 | } 21 | $this = $("#sendMessageButton"); 22 | $this.prop("disabled", true); // Disable submit button until AJAX call is complete to prevent duplicate messages 23 | $.ajax({ 24 | url: "/assets/mail/contact_me.php", 25 | type: "POST", 26 | data: { 27 | name: name, 28 | phone: phone, 29 | email: email, 30 | message: message, 31 | }, 32 | cache: false, 33 | success: function () { 34 | // Success message 35 | $("#success").html("
"); 36 | $("#success > .alert-success") 37 | .html( 38 | ""); 41 | $("#success > .alert-success").append( 42 | "Your message has been sent. " 43 | ); 44 | $("#success > .alert-success").append("
"); 45 | //clear all fields 46 | $("#contactForm").trigger("reset"); 47 | }, 48 | error: function () { 49 | // Fail message 50 | $("#success").html("
"); 51 | $("#success > .alert-danger") 52 | .html( 53 | ""); 56 | $("#success > .alert-danger").append( 57 | $("").text( 58 | "Sorry " + 59 | firstName + 60 | ", it seems that my mail server is not responding. Please try again later!" 61 | ) 62 | ); 63 | $("#success > .alert-danger").append("
"); 64 | //clear all fields 65 | $("#contactForm").trigger("reset"); 66 | }, 67 | complete: function () { 68 | setTimeout(function () { 69 | $this.prop("disabled", false); // Re-enable submit button when AJAX call is complete 70 | }, 1000); 71 | }, 72 | }); 73 | }, 74 | filter: function () { 75 | return $(this).is(":visible"); 76 | }, 77 | }); 78 | 79 | $('a[data-toggle="tab"]').click(function (e) { 80 | e.preventDefault(); 81 | $(this).tab("show"); 82 | }); 83 | }); 84 | 85 | /*When clicking on Full hide fail/success boxes */ 86 | $("#name").focus(function () { 87 | $("#success").html(""); 88 | }); 89 | -------------------------------------------------------------------------------- /src/Freelancer.OrchardCore/Recipes/Snippets/LandingPage.liquid: -------------------------------------------------------------------------------- 1 |
2 |
3 | 4 | {{ Model.ContentItem.Content.LandingPage.Name.Text }} 5 | 6 |

{{ Model.ContentItem.Content.LandingPage.Name.Text }}

7 | 8 |
9 |
10 |
11 | 12 |
13 |
14 |
15 | 16 |

{{ Model.ContentItem.Content.LandingPage.Tagline.Text }}

17 |
18 |
19 | {% if Model.ContentItem.Content.Portfolio.ContentItems.size > 0 %} 20 |
21 |
22 | 23 |

Portfolio

24 | 25 |
26 |
27 |
28 | 29 |
30 |
31 |
32 | 33 |
34 | {% for project in Model.ContentItem.Content.Portfolio.ContentItems %} 35 |
36 |
37 |
38 |
39 | 40 |
41 |
42 | {{ project.TitlePart.Title }} 43 |
44 |
45 | {% endfor %} 46 |
47 |
48 |
49 | {% endif %} 50 | {% if Model.ContentItem.Content.Sections.ContentItems.size > 0 %} 51 | {% for section in Model.ContentItem.Content.Sections.ContentItems %} 52 | {{ section.HtmlBodyPart.Html | raw }} 53 | {% endfor %} 54 | {% endif %} 55 | {% if Model.ContentItem.Content.Portfolio.ContentItems.size > 0 %} 56 | {% for project in Model.ContentItem.Content.Portfolio.ContentItems %} 57 | 94 | {% endfor %} 95 | {% endif %} -------------------------------------------------------------------------------- /src/Freelancer.OrchardCore/wwwroot/img/profiles/avataaars.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 38 | Created with getavataaars.com 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 106 | 107 | 108 | 110 | 111 | 112 | 113 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 189 | 191 | 192 | 193 | 195 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 | -------------------------------------------------------------------------------- /src/Freelancer.OrchardCore/Recipes/freelancer.recipe.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Freelancer", 3 | "displayName": "Freelancer", 4 | "description": "Portfolio website for freelancers.", 5 | "author": "David Hayden", 6 | "website": "https://www.davidhayden.me", 7 | "version": "1.0.0-rc2", 8 | "issetuprecipe": true, 9 | "categories": [ 10 | "default" 11 | ], 12 | "tags": [ 13 | "freelancer" 14 | ], 15 | "variables": { 16 | "now": "[js: new Date().toISOString()]" 17 | }, 18 | "steps": [ 19 | { 20 | "name": "feature", 21 | "disable": [], 22 | "enable": [ 23 | "OrchardCore.HomeRoute", 24 | "OrchardCore.Admin", 25 | "OrchardCore.Diagnostics", 26 | "OrchardCore.DynamicCache", 27 | "OrchardCore.Features", 28 | "OrchardCore.Navigation", 29 | "OrchardCore.Recipes", 30 | "OrchardCore.Resources", 31 | "OrchardCore.Roles", 32 | "OrchardCore.Settings", 33 | "OrchardCore.Themes", 34 | "OrchardCore.Users", 35 | 36 | "OrchardCore.Alias", 37 | "OrchardCore.Autoroute", 38 | "OrchardCore.Html", 39 | "OrchardCore.ContentFields", 40 | "OrchardCore.ContentPreview", 41 | "OrchardCore.Contents", 42 | "OrchardCore.Contents.FileContentDefinition", 43 | "OrchardCore.ContentTypes", 44 | "OrchardCore.CustomSettings", 45 | "OrchardCore.Deployment", 46 | "OrchardCore.Deployment.Remote", 47 | "OrchardCore.Feeds", 48 | "OrchardCore.Flows", 49 | "OrchardCore.Layers", 50 | "OrchardCore.Lists", 51 | "OrchardCore.Liquid", 52 | "OrchardCore.Markdown", 53 | "OrchardCore.Media", 54 | "OrchardCore.Menu", 55 | "OrchardCore.Queries", 56 | "OrchardCore.Title", 57 | "OrchardCore.Templates", 58 | "OrchardCore.Widgets", 59 | 60 | "Freelancer.OrchardCore", 61 | "TheAdmin", 62 | "SafeMode" 63 | ] 64 | }, 65 | { 66 | "name": "themes", 67 | "admin": "TheAdmin", 68 | "site": "Freelancer.OrchardCore" 69 | }, 70 | { 71 | "name": "settings", 72 | "HomeRoute": { 73 | "Action": "Display", 74 | "Controller": "Item", 75 | "Area": "OrchardCore.Contents", 76 | "ContentItemId": "[js:uuid()]" 77 | }, 78 | "LayerSettings": { 79 | "Zones": [ 80 | "Footer", 81 | "Copyright" 82 | ] 83 | } 84 | }, 85 | { 86 | "name": "ContentDefinition", 87 | "ContentTypes": [ 88 | { 89 | "Name": "HtmlWidget", 90 | "DisplayName": "Html", 91 | "Settings": { 92 | "ContentTypeSettings": { 93 | "Creatable": "False", 94 | "Draftable": "True", 95 | "Versionable": "True", 96 | "Listable": "False", 97 | "Securable": "True", 98 | "Stereotype": "Widget" 99 | } 100 | }, 101 | "ContentTypePartDefinitionRecords": [ 102 | { 103 | "PartName": "HtmlWidget", 104 | "Name": "HtmlWidget", 105 | "Settings": { 106 | "ContentTypePartSettings": { 107 | "Position": "0" 108 | } 109 | } 110 | } 111 | ] 112 | }, 113 | { 114 | "Name": "LandingPage", 115 | "DisplayName": "Landing Page", 116 | "Settings": { 117 | "ContentTypeSettings": { 118 | "Creatable": "True", 119 | "Draftable": "True", 120 | "Versionable": "True", 121 | "Listable": "True", 122 | "Securable": "True" 123 | } 124 | }, 125 | "ContentTypePartDefinitionRecords": [ 126 | { 127 | "PartName": "LandingPage", 128 | "Name": "LandingPage", 129 | "Settings": { 130 | "ContentTypePartSettings": { 131 | "Position": "8" 132 | } 133 | } 134 | }, 135 | { 136 | "PartName": "AutoroutePart", 137 | "Name": "AutoroutePart", 138 | "Settings": { 139 | "AutoroutePartSettings": { 140 | "Pattern": "{{ ContentItem | display_text | slugify }}", 141 | "AllowCustomPath": "True", 142 | "ShowHomepageOption": "True" 143 | }, 144 | "ContentIndexSettings": { 145 | "Included": false, 146 | "Stored": false, 147 | "Analyzed": false, 148 | "Sanitized": false, 149 | "Tokenized": false 150 | }, 151 | "ContentTypePartSettings": { 152 | "Position": "1" 153 | } 154 | } 155 | }, 156 | { 157 | "PartName": "TitlePart", 158 | "Name": "TitlePart", 159 | "Settings": { 160 | "ContentTypePartSettings": { 161 | "Position": "0" 162 | } 163 | } 164 | }, 165 | { 166 | "PartName": "BagPart", 167 | "Name": "Portfolio", 168 | "Settings": { 169 | "BagPartSettings": { 170 | "ContainedContentTypes": [ 171 | "Project" 172 | ] 173 | }, 174 | "ContentIndexSettings": { 175 | "Included": false, 176 | "Stored": false, 177 | "Analyzed": false, 178 | "Sanitized": false, 179 | "Tokenized": false 180 | }, 181 | "ContentTypePartSettings": { 182 | "DisplayName": "Portfolio", 183 | "Description": "A list of client projects.", 184 | "Position": "2" 185 | } 186 | } 187 | }, 188 | { 189 | "PartName": "BagPart", 190 | "Name": "Sections", 191 | "Settings": { 192 | "BagPartSettings": { 193 | "ContainedContentTypes": [ 194 | "Section" 195 | ] 196 | }, 197 | "ContentIndexSettings": { 198 | "Included": false, 199 | "Stored": false, 200 | "Analyzed": false, 201 | "Sanitized": false, 202 | "Tokenized": false 203 | }, 204 | "ContentTypePartSettings": { 205 | "DisplayName": "Sections", 206 | "Description": "A list of sections appearing after portfolio.", 207 | "Position": "2" 208 | } 209 | } 210 | } 211 | ] 212 | }, 213 | { 214 | "Name": "Project", 215 | "DisplayName": "Project", 216 | "ContentTypePartDefinitionRecords": [ 217 | { 218 | "PartName": "Project", 219 | "Name": "Project", 220 | "Settings": { 221 | "ContentTypePartSettings": { 222 | "Position": "2" 223 | } 224 | } 225 | }, 226 | { 227 | "PartName": "HtmlBodyPart", 228 | "Name": "HtmlBodyPart", 229 | "Settings": { 230 | "ContentTypePartSettings": { 231 | "Position": "1" 232 | } 233 | } 234 | }, 235 | { 236 | "PartName": "TitlePart", 237 | "Name": "TitlePart", 238 | "Settings": { 239 | "ContentTypePartSettings": { 240 | "Position": "0" 241 | } 242 | } 243 | } 244 | ] 245 | }, 246 | { 247 | "Name": "Section", 248 | "DisplayName": "Section", 249 | "ContentTypePartDefinitionRecords": [ 250 | { 251 | "PartName": "Section", 252 | "Name": "Section", 253 | "Settings": { 254 | "ContentTypePartSettings": { 255 | "Position": "2" 256 | } 257 | } 258 | }, 259 | { 260 | "PartName": "HtmlBodyPart", 261 | "Name": "HtmlBodyPart", 262 | "Settings": { 263 | "ContentTypePartSettings": { 264 | "Position": "1" 265 | } 266 | } 267 | }, 268 | { 269 | "PartName": "TitlePart", 270 | "Name": "TitlePart", 271 | "Settings": { 272 | "ContentTypePartSettings": { 273 | "Position": "0" 274 | } 275 | } 276 | } 277 | ] 278 | }, 279 | { 280 | "Name": "LiquidWidget", 281 | "DisplayName": "Liquid", 282 | "Settings": { 283 | "ContentTypeSettings": { 284 | "Creatable": "False", 285 | "Draftable": "True", 286 | "Versionable": "True", 287 | "Listable": "True", 288 | "Securable": "True", 289 | "Stereotype": "Widget" 290 | } 291 | }, 292 | "ContentTypePartDefinitionRecords": [ 293 | { 294 | "PartName": "LiquidPart", 295 | "Name": "LiquidPart", 296 | "Settings": { 297 | "ContentTypePartSettings": { 298 | "Position": "0" 299 | } 300 | } 301 | } 302 | ] 303 | } 304 | ], 305 | "ContentParts": [ 306 | { 307 | "Name": "LandingPage", 308 | "Settings": {}, 309 | "ContentPartFieldDefinitionRecords": [ 310 | { 311 | "FieldName": "TextField", 312 | "Name": "Name", 313 | "Settings": { 314 | "ContentPartFieldSettings": { 315 | "DisplayName": "Name", 316 | "Position": "0" 317 | }, 318 | "ContentIndexSettings": { 319 | "Included": false, 320 | "Stored": false, 321 | "Analyzed": false, 322 | "Sanitized": false, 323 | "Tokenized": false 324 | } 325 | } 326 | }, 327 | { 328 | "FieldName": "TextField", 329 | "Name": "Tagline", 330 | "Settings": { 331 | "ContentPartFieldSettings": { 332 | "DisplayName": "Tagline", 333 | "Position": "1" 334 | }, 335 | "ContentIndexSettings": { 336 | "Included": false, 337 | "Stored": false, 338 | "Analyzed": false, 339 | "Sanitized": false, 340 | "Tokenized": false 341 | } 342 | } 343 | }, 344 | { 345 | "FieldName": "MediaField", 346 | "Name": "Photo", 347 | "Settings": { 348 | "ContentPartFieldSettings": { 349 | "DisplayName": "Photo", 350 | "Position": "2" 351 | }, 352 | "MediaFieldSettings": { 353 | "Required": true, 354 | "Multiple": false 355 | }, 356 | "ContentIndexSettings": { 357 | "Included": false, 358 | "Stored": false, 359 | "Analyzed": false, 360 | "Sanitized": false, 361 | "Tokenized": false 362 | } 363 | } 364 | } 365 | ] 366 | }, 367 | { 368 | "Name": "Project", 369 | "Settings": {}, 370 | "ContentPartFieldDefinitionRecords": [ 371 | { 372 | "FieldName": "MediaField", 373 | "Name": "Image", 374 | "Settings": { 375 | "ContentPartFieldSettings": { 376 | "DisplayName": "Image", 377 | "Position": "1" 378 | }, 379 | "MediaFieldSettings": { 380 | "Required": true, 381 | "Multiple": false 382 | }, 383 | "ContentIndexSettings": { 384 | "Included": false, 385 | "Stored": false, 386 | "Analyzed": false, 387 | "Sanitized": false, 388 | "Tokenized": false 389 | } 390 | } 391 | } 392 | ] 393 | }, 394 | { 395 | "Name": "HtmlWidget", 396 | "Settings": {}, 397 | "ContentPartFieldDefinitionRecords": [ 398 | { 399 | "FieldName": "HtmlField", 400 | "Name": "Content", 401 | "Settings": { 402 | "ContentPartFieldSettings": { 403 | "DisplayName": "Content", 404 | "Editor": "Multiline", 405 | "Position": "0" 406 | }, 407 | "ContentIndexSettings": { 408 | "Included": false, 409 | "Stored": false, 410 | "Analyzed": false, 411 | "Sanitized": false, 412 | "Tokenized": false 413 | } 414 | } 415 | } 416 | ] 417 | } 418 | ] 419 | }, 420 | { 421 | "name": "media", 422 | "Files": [ 423 | { 424 | "TargetPath": "img/profiles/avataaars.svg", 425 | "SourcePath": "../wwwroot/img/profiles/avataaars.svg" 426 | }, 427 | { 428 | "TargetPath": "img/portfolio/cabin.png", 429 | "SourcePath": "../wwwroot/img/portfolio/cabin.png" 430 | }, 431 | { 432 | "TargetPath": "img/portfolio/cake.png", 433 | "SourcePath": "../wwwroot/img/portfolio/cake.png" 434 | }, 435 | { 436 | "TargetPath": "img/portfolio/circus.png", 437 | "SourcePath": "../wwwroot/img/portfolio/circus.png" 438 | }, 439 | { 440 | "TargetPath": "img/portfolio/game.png", 441 | "SourcePath": "../wwwroot/img/portfolio/game.png" 442 | }, 443 | { 444 | "TargetPath": "img/portfolio/safe.png", 445 | "SourcePath": "../wwwroot/img/portfolio/safe.png" 446 | }, 447 | { 448 | "TargetPath": "img/portfolio/submarine.png", 449 | "SourcePath": "../wwwroot/img/portfolio/submarine.png" 450 | } 451 | ] 452 | }, 453 | { 454 | "name": "content", 455 | "Data": [ 456 | { 457 | "ContentItemId": "[js:uuid()]", 458 | "ContentItemVersionId": "[js:uuid()]", 459 | "ContentType": "Menu", 460 | "DisplayText": "Main Menu", 461 | "Latest": true, 462 | "Published": true, 463 | "ModifiedUtc": "[js: variables('now')]", 464 | "PublishedUtc": "[js: variables('now')]", 465 | "CreatedUtc": "[js: variables('now')]", 466 | "Owner": "[js: parameters('AdminUsername')]", 467 | "Author": "[js: parameters('AdminUsername')]", 468 | "MenuPart": {}, 469 | "TitlePart": { 470 | "Title": "Main Menu" 471 | }, 472 | "MenuItemsListPart": { 473 | "MenuItems": [ 474 | { 475 | "ContentType": "LinkMenuItem", 476 | "ContentItemId": "[js:uuid()]", 477 | "LinkMenuItemPart": { 478 | "Name": "Portfolio", 479 | "Url": "~/#portfolio" 480 | } 481 | }, 482 | { 483 | "ContentType": "LinkMenuItem", 484 | "ContentItemId": "[js:uuid()]", 485 | "LinkMenuItemPart": { 486 | "Name": "About", 487 | "Url": "~/#about" 488 | } 489 | }, 490 | { 491 | "ContentType": "LinkMenuItem", 492 | "ContentItemId": "[js:uuid()]", 493 | "LinkMenuItemPart": { 494 | "Name": "Contact", 495 | "Url": "~/#contact" 496 | } 497 | } 498 | ] 499 | }, 500 | "AliasPart": { 501 | "Alias": "main-menu" 502 | } 503 | }, 504 | { 505 | "ContentItemId": "[js:uuid()]", 506 | "ContentItemVersionId": "[js:uuid()]", 507 | "ContentType": "LandingPage", 508 | "DisplayText": "Homepage", 509 | "Latest": true, 510 | "Published": true, 511 | "ModifiedUtc": "[js: variables('now')]", 512 | "PublishedUtc": "[js: variables('now')]", 513 | "CreatedUtc": "[js: variables('now')]", 514 | "Owner": "[js: parameters('AdminUsername')]", 515 | "Author": "[js: parameters('AdminUsername')]", 516 | "LandingPage": { 517 | "Name": { 518 | "Text": "Start Bootstrap" 519 | }, 520 | "Tagline": { 521 | "Text": "Web Developer - Graphic Artist - User Experience Designer" 522 | }, 523 | "Photo": { 524 | "Paths": [ 525 | "/img/profiles/avataaars.svg" 526 | ] 527 | } 528 | }, 529 | "AutoroutePart": { 530 | "Path": "home-page", 531 | "SetHomepage": true 532 | }, 533 | "TitlePart": { 534 | "Title": "Homepage" 535 | }, 536 | "Portfolio": { 537 | "ContentItems": [ 538 | { 539 | "ContentItemId": "[js:uuid()]", 540 | "ContentItemVersionId": "[js:uuid()]", 541 | "ContentType": "Project", 542 | "DisplayText": "Cabin", 543 | "Latest": false, 544 | "Published": false, 545 | "ModifiedUtc": "[js: variables('now')]", 546 | "PublishedUtc": null, 547 | "CreatedUtc": null, 548 | "Owner": null, 549 | "Author": "[js: parameters('AdminUsername')]", 550 | "Project": { 551 | "Image": { 552 | "Paths": [ 553 | "/img/portfolio/cabin.png" 554 | ] 555 | } 556 | }, 557 | "HtmlBodyPart": { 558 | "Html": "Lorem ipsum dolor sit amet, consectetur adipisicing elit. Est blanditiis dolorem culpa incidunt minus dignissimos deserunt repellat aperiam quasi sunt officia expedita beatae cupiditate, maiores repudiandae, nostrum, reiciendis facere nemo!" 559 | }, 560 | "TitlePart": { 561 | "Title": "Cabin" 562 | } 563 | }, 564 | { 565 | "ContentItemId": "[js:uuid()]", 566 | "ContentItemVersionId": "[js:uuid()]", 567 | "ContentType": "Project", 568 | "DisplayText": "Cake", 569 | "Latest": false, 570 | "Published": false, 571 | "ModifiedUtc": "[js: variables('now')]", 572 | "PublishedUtc": null, 573 | "CreatedUtc": null, 574 | "Owner": null, 575 | "Author": "[js: parameters('AdminUsername')]", 576 | "Project": { 577 | "Image": { 578 | "Paths": [ 579 | "img/portfolio/cake.png" 580 | ] 581 | } 582 | }, 583 | "HtmlBodyPart": { 584 | "Html": "Lorem ipsum dolor sit amet, consectetur adipisicing elit. Est blanditiis dolorem culpa incidunt minus dignissimos deserunt repellat aperiam quasi sunt officia expedita beatae cupiditate, maiores repudiandae, nostrum, reiciendis facere nemo!" 585 | }, 586 | "TitlePart": { 587 | "Title": "Cake" 588 | } 589 | }, 590 | { 591 | "ContentItemId": "[js:uuid()]", 592 | "ContentItemVersionId": "[js:uuid()]", 593 | "ContentType": "Project", 594 | "DisplayText": "Circus", 595 | "Latest": false, 596 | "Published": false, 597 | "ModifiedUtc": "[js: variables('now')]", 598 | "PublishedUtc": null, 599 | "CreatedUtc": null, 600 | "Owner": null, 601 | "Author": "[js: parameters('AdminUsername')]", 602 | "Project": { 603 | "Image": { 604 | "Paths": [ 605 | "img/portfolio/circus.png" 606 | ] 607 | } 608 | }, 609 | "HtmlBodyPart": { 610 | "Html": "Lorem ipsum dolor sit amet, consectetur adipisicing elit. Est blanditiis dolorem culpa incidunt minus dignissimos deserunt repellat aperiam quasi sunt officia expedita beatae cupiditate, maiores repudiandae, nostrum, reiciendis facere nemo!" 611 | }, 612 | "TitlePart": { 613 | "Title": "Circus" 614 | } 615 | }, 616 | { 617 | "ContentItemId": "[js:uuid()]", 618 | "ContentItemVersionId": "[js:uuid()]", 619 | "ContentType": "Project", 620 | "DisplayText": "Game", 621 | "Latest": false, 622 | "Published": false, 623 | "ModifiedUtc": "[js: variables('now')]", 624 | "PublishedUtc": null, 625 | "CreatedUtc": null, 626 | "Owner": null, 627 | "Author": "[js: parameters('AdminUsername')]", 628 | "Project": { 629 | "Image": { 630 | "Paths": [ 631 | "img/portfolio/game.png" 632 | ] 633 | } 634 | }, 635 | "HtmlBodyPart": { 636 | "Html": "Lorem ipsum dolor sit amet, consectetur adipisicing elit. Est blanditiis dolorem culpa incidunt minus dignissimos deserunt repellat aperiam quasi sunt officia expedita beatae cupiditate, maiores repudiandae, nostrum, reiciendis facere nemo!" 637 | }, 638 | "TitlePart": { 639 | "Title": "Game" 640 | } 641 | }, 642 | { 643 | "ContentItemId": "[js:uuid()]", 644 | "ContentItemVersionId": "[js:uuid()]", 645 | "ContentType": "Project", 646 | "DisplayText": "Safe", 647 | "Latest": false, 648 | "Published": false, 649 | "ModifiedUtc": "[js: variables('now')]", 650 | "PublishedUtc": null, 651 | "CreatedUtc": null, 652 | "Owner": null, 653 | "Author": "[js: parameters('AdminUsername')]", 654 | "Project": { 655 | "Image": { 656 | "Paths": [ 657 | "img/portfolio/safe.png" 658 | ] 659 | } 660 | }, 661 | "HtmlBodyPart": { 662 | "Html": "Lorem ipsum dolor sit amet, consectetur adipisicing elit. Est blanditiis dolorem culpa incidunt minus dignissimos deserunt repellat aperiam quasi sunt officia expedita beatae cupiditate, maiores repudiandae, nostrum, reiciendis facere nemo!" 663 | }, 664 | "TitlePart": { 665 | "Title": "Safe" 666 | } 667 | }, 668 | { 669 | "ContentItemId": "[js:uuid()]", 670 | "ContentItemVersionId": "[js:uuid()]", 671 | "ContentType": "Project", 672 | "DisplayText": "Submarine", 673 | "Latest": false, 674 | "Published": false, 675 | "ModifiedUtc": "[js: variables('now')]", 676 | "PublishedUtc": null, 677 | "CreatedUtc": null, 678 | "Owner": null, 679 | "Author": "[js: parameters('AdminUsername')]", 680 | "Project": { 681 | "Image": { 682 | "Paths": [ 683 | "img/portfolio/submarine.png" 684 | ] 685 | } 686 | }, 687 | "HtmlBodyPart": { 688 | "Html": "Lorem ipsum dolor sit amet, consectetur adipisicing elit. Est blanditiis dolorem culpa incidunt minus dignissimos deserunt repellat aperiam quasi sunt officia expedita beatae cupiditate, maiores repudiandae, nostrum, reiciendis facere nemo!" 689 | }, 690 | "TitlePart": { 691 | "Title": "Submarine" 692 | } 693 | } 694 | ] 695 | }, 696 | "Sections": { 697 | "ContentItems": [ 698 | { 699 | "ContentItemId": "[js:uuid()]", 700 | "ContentItemVersionId": "[js:uuid()]", 701 | "ContentType": "Section", 702 | "DisplayText": "About", 703 | "Latest": false, 704 | "Published": false, 705 | "ModifiedUtc": "[js: variables('now')]", 706 | "PublishedUtc": null, 707 | "CreatedUtc": null, 708 | "Owner": null, 709 | "Author": "[js: parameters('AdminUsername')]", 710 | "HtmlBodyPart": { 711 | "Html": "[file:text('Snippets/About.html')]" 712 | }, 713 | "TitlePart": { 714 | "Title": "About" 715 | } 716 | }, 717 | { 718 | "ContentItemId": "[js:uuid()]", 719 | "ContentItemVersionId": "[js:uuid()]", 720 | "ContentType": "Section", 721 | "DisplayText": "Contact", 722 | "Latest": false, 723 | "Published": false, 724 | "ModifiedUtc": "[js: variables('now')]", 725 | "PublishedUtc": null, 726 | "CreatedUtc": null, 727 | "Owner": null, 728 | "Author": "[js: parameters('AdminUsername')]", 729 | "HtmlBodyPart": { 730 | "Html": "[file:text('Snippets/Contact.html')]" 731 | }, 732 | "TitlePart": { 733 | "Title": "Contact" 734 | } 735 | } 736 | ] 737 | } 738 | }, 739 | { 740 | "ContentItemId": "[js: uuid()]", 741 | "ContentType": "HtmlWidget", 742 | "DisplayText": "Footer", 743 | "Latest": true, 744 | "Published": true, 745 | "Owner": "[js: parameters('AdminUsername')]", 746 | "Author": "[js: parameters('AdminUsername')]", 747 | "LayerMetadata": { 748 | "Title": "Footer", 749 | "Layer": "Always", 750 | "Zone": "Footer", 751 | "RenderTitle": false, 752 | "Position": 10 753 | }, 754 | "HtmlWidget": { 755 | "Content": { 756 | "Html": "[file:text('Snippets/Footer.html')]" 757 | } 758 | } 759 | }, 760 | { 761 | "ContentItemId": "[js: uuid()]", 762 | "ContentType": "HtmlWidget", 763 | "DisplayText": "Copyright", 764 | "Latest": true, 765 | "Published": true, 766 | "Owner": "[js: parameters('AdminUsername')]", 767 | "Author": "[js: parameters('AdminUsername')]", 768 | "LayerMetadata": { 769 | "Title": "Copyright", 770 | "Layer": "Always", 771 | "Zone": "Copyright", 772 | "RenderTitle": false, 773 | "Position": 10 774 | }, 775 | "HtmlWidget": { 776 | "Content": { 777 | "Html": "[file:text('Snippets/Copyright.html')]" 778 | } 779 | } 780 | } 781 | ] 782 | }, 783 | { 784 | "name": "layers", 785 | "Layers": [ 786 | { 787 | "Name": "Always", 788 | "Rule": "true", 789 | "Description": "The widgets in this layer are displayed on any page of this site." 790 | }, 791 | { 792 | "Name": "Homepage", 793 | "Rule": "isHomepage()", 794 | "Description": "The widgets in this layer are only displayed on the homepage." 795 | } 796 | ] 797 | }, 798 | { 799 | "name": "Templates", 800 | "Templates": { 801 | "Content__LandingPage": { 802 | "Description": "A template for the Landing Page content type", 803 | "Content": "[file:text('Snippets/LandingPage.liquid')]" 804 | } 805 | } 806 | } 807 | ] 808 | } -------------------------------------------------------------------------------- /src/Freelancer.OrchardCore/wwwroot/js/jqBootstrapValidation.js: -------------------------------------------------------------------------------- 1 | /* jqBootstrapValidation 2 | * A plugin for automating validation on Twitter Bootstrap formatted forms. 3 | * 4 | * v1.3.6 5 | * 6 | * License: MIT - see LICENSE file 7 | * 8 | * http://ReactiveRaven.github.com/jqBootstrapValidation/ 9 | */ 10 | 11 | (function( $ ){ 12 | 13 | var createdElements = []; 14 | 15 | var defaults = { 16 | options: { 17 | prependExistingHelpBlock: false, 18 | sniffHtml: true, // sniff for 'required', 'maxlength', etc 19 | preventSubmit: true, // stop the form submit event from firing if validation fails 20 | submitError: false, // function called if there is an error when trying to submit 21 | submitSuccess: false, // function called just before a successful submit event is sent to the server 22 | semanticallyStrict: false, // set to true to tidy up generated HTML output 23 | autoAdd: { 24 | helpBlocks: true 25 | }, 26 | filter: function () { 27 | // return $(this).is(":visible"); // only validate elements you can see 28 | return true; // validate everything 29 | } 30 | }, 31 | methods: { 32 | init : function( options ) { 33 | 34 | var settings = $.extend(true, {}, defaults); 35 | 36 | settings.options = $.extend(true, settings.options, options); 37 | 38 | var $siblingElements = this; 39 | 40 | var uniqueForms = $.unique( 41 | $siblingElements.map( function () { 42 | return $(this).parents("form")[0]; 43 | }).toArray() 44 | ); 45 | 46 | $(uniqueForms).bind("submit", function (e) { 47 | var $form = $(this); 48 | var warningsFound = 0; 49 | var $inputs = $form.find("input,textarea,select").not("[type=submit],[type=image]").filter(settings.options.filter); 50 | $inputs.trigger("submit.validation").trigger("validationLostFocus.validation"); 51 | 52 | $inputs.each(function (i, el) { 53 | var $this = $(el), 54 | $controlGroup = $this.parents(".control-group").first(); 55 | if ( 56 | $controlGroup.hasClass("warning") 57 | ) { 58 | $controlGroup.removeClass("warning").addClass("error"); 59 | warningsFound++; 60 | } 61 | }); 62 | 63 | $inputs.trigger("validationLostFocus.validation"); 64 | 65 | if (warningsFound) { 66 | if (settings.options.preventSubmit) { 67 | e.preventDefault(); 68 | } 69 | $form.addClass("error"); 70 | if ($.isFunction(settings.options.submitError)) { 71 | settings.options.submitError($form, e, $inputs.jqBootstrapValidation("collectErrors", true)); 72 | } 73 | } else { 74 | $form.removeClass("error"); 75 | if ($.isFunction(settings.options.submitSuccess)) { 76 | settings.options.submitSuccess($form, e); 77 | } 78 | } 79 | }); 80 | 81 | return this.each(function(){ 82 | 83 | // Get references to everything we're interested in 84 | var $this = $(this), 85 | $controlGroup = $this.parents(".control-group").first(), 86 | $helpBlock = $controlGroup.find(".help-block").first(), 87 | $form = $this.parents("form").first(), 88 | validatorNames = []; 89 | 90 | // create message container if not exists 91 | if (!$helpBlock.length && settings.options.autoAdd && settings.options.autoAdd.helpBlocks) { 92 | $helpBlock = $('
'); 93 | $controlGroup.find('.controls').append($helpBlock); 94 | createdElements.push($helpBlock[0]); 95 | } 96 | 97 | // ============================================================= 98 | // SNIFF HTML FOR VALIDATORS 99 | // ============================================================= 100 | 101 | // *snort sniff snuffle* 102 | 103 | if (settings.options.sniffHtml) { 104 | var message = ""; 105 | // --------------------------------------------------------- 106 | // PATTERN 107 | // --------------------------------------------------------- 108 | if ($this.attr("pattern") !== undefined) { 109 | message = "Not in the expected format"; 110 | if ($this.data("validationPatternMessage")) { 111 | message = $this.data("validationPatternMessage"); 112 | } 113 | $this.data("validationPatternMessage", message); 114 | $this.data("validationPatternRegex", $this.attr("pattern")); 115 | } 116 | // --------------------------------------------------------- 117 | // MAX 118 | // --------------------------------------------------------- 119 | if ($this.attr("max") !== undefined || $this.attr("aria-valuemax") !== undefined) { 120 | var max = ($this.attr("max") !== undefined ? $this.attr("max") : $this.attr("aria-valuemax")); 121 | message = "Too high: Maximum of '" + max + "'"; 122 | if ($this.data("validationMaxMessage")) { 123 | message = $this.data("validationMaxMessage"); 124 | } 125 | $this.data("validationMaxMessage", message); 126 | $this.data("validationMaxMax", max); 127 | } 128 | // --------------------------------------------------------- 129 | // MIN 130 | // --------------------------------------------------------- 131 | if ($this.attr("min") !== undefined || $this.attr("aria-valuemin") !== undefined) { 132 | var min = ($this.attr("min") !== undefined ? $this.attr("min") : $this.attr("aria-valuemin")); 133 | message = "Too low: Minimum of '" + min + "'"; 134 | if ($this.data("validationMinMessage")) { 135 | message = $this.data("validationMinMessage"); 136 | } 137 | $this.data("validationMinMessage", message); 138 | $this.data("validationMinMin", min); 139 | } 140 | // --------------------------------------------------------- 141 | // MAXLENGTH 142 | // --------------------------------------------------------- 143 | if ($this.attr("maxlength") !== undefined) { 144 | message = "Too long: Maximum of '" + $this.attr("maxlength") + "' characters"; 145 | if ($this.data("validationMaxlengthMessage")) { 146 | message = $this.data("validationMaxlengthMessage"); 147 | } 148 | $this.data("validationMaxlengthMessage", message); 149 | $this.data("validationMaxlengthMaxlength", $this.attr("maxlength")); 150 | } 151 | // --------------------------------------------------------- 152 | // MINLENGTH 153 | // --------------------------------------------------------- 154 | if ($this.attr("minlength") !== undefined) { 155 | message = "Too short: Minimum of '" + $this.attr("minlength") + "' characters"; 156 | if ($this.data("validationMinlengthMessage")) { 157 | message = $this.data("validationMinlengthMessage"); 158 | } 159 | $this.data("validationMinlengthMessage", message); 160 | $this.data("validationMinlengthMinlength", $this.attr("minlength")); 161 | } 162 | // --------------------------------------------------------- 163 | // REQUIRED 164 | // --------------------------------------------------------- 165 | if ($this.attr("required") !== undefined || $this.attr("aria-required") !== undefined) { 166 | message = settings.builtInValidators.required.message; 167 | if ($this.data("validationRequiredMessage")) { 168 | message = $this.data("validationRequiredMessage"); 169 | } 170 | $this.data("validationRequiredMessage", message); 171 | } 172 | // --------------------------------------------------------- 173 | // NUMBER 174 | // --------------------------------------------------------- 175 | if ($this.attr("type") !== undefined && $this.attr("type").toLowerCase() === "number") { 176 | message = settings.builtInValidators.number.message; 177 | if ($this.data("validationNumberMessage")) { 178 | message = $this.data("validationNumberMessage"); 179 | } 180 | $this.data("validationNumberMessage", message); 181 | } 182 | // --------------------------------------------------------- 183 | // EMAIL 184 | // --------------------------------------------------------- 185 | if ($this.attr("type") !== undefined && $this.attr("type").toLowerCase() === "email") { 186 | message = "Not a valid email address"; 187 | if ($this.data("validationValidemailMessage")) { 188 | message = $this.data("validationValidemailMessage"); 189 | } else if ($this.data("validationEmailMessage")) { 190 | message = $this.data("validationEmailMessage"); 191 | } 192 | $this.data("validationValidemailMessage", message); 193 | } 194 | // --------------------------------------------------------- 195 | // MINCHECKED 196 | // --------------------------------------------------------- 197 | if ($this.attr("minchecked") !== undefined) { 198 | message = "Not enough options checked; Minimum of '" + $this.attr("minchecked") + "' required"; 199 | if ($this.data("validationMincheckedMessage")) { 200 | message = $this.data("validationMincheckedMessage"); 201 | } 202 | $this.data("validationMincheckedMessage", message); 203 | $this.data("validationMincheckedMinchecked", $this.attr("minchecked")); 204 | } 205 | // --------------------------------------------------------- 206 | // MAXCHECKED 207 | // --------------------------------------------------------- 208 | if ($this.attr("maxchecked") !== undefined) { 209 | message = "Too many options checked; Maximum of '" + $this.attr("maxchecked") + "' required"; 210 | if ($this.data("validationMaxcheckedMessage")) { 211 | message = $this.data("validationMaxcheckedMessage"); 212 | } 213 | $this.data("validationMaxcheckedMessage", message); 214 | $this.data("validationMaxcheckedMaxchecked", $this.attr("maxchecked")); 215 | } 216 | } 217 | 218 | // ============================================================= 219 | // COLLECT VALIDATOR NAMES 220 | // ============================================================= 221 | 222 | // Get named validators 223 | if ($this.data("validation") !== undefined) { 224 | validatorNames = $this.data("validation").split(","); 225 | } 226 | 227 | // Get extra ones defined on the element's data attributes 228 | $.each($this.data(), function (i, el) { 229 | var parts = i.replace(/([A-Z])/g, ",$1").split(","); 230 | if (parts[0] === "validation" && parts[1]) { 231 | validatorNames.push(parts[1]); 232 | } 233 | }); 234 | 235 | // ============================================================= 236 | // NORMALISE VALIDATOR NAMES 237 | // ============================================================= 238 | 239 | var validatorNamesToInspect = validatorNames; 240 | var newValidatorNamesToInspect = []; 241 | 242 | do // repeatedly expand 'shortcut' validators into their real validators 243 | { 244 | // Uppercase only the first letter of each name 245 | $.each(validatorNames, function (i, el) { 246 | validatorNames[i] = formatValidatorName(el); 247 | }); 248 | 249 | // Remove duplicate validator names 250 | validatorNames = $.unique(validatorNames); 251 | 252 | // Pull out the new validator names from each shortcut 253 | newValidatorNamesToInspect = []; 254 | $.each(validatorNamesToInspect, function(i, el) { 255 | if ($this.data("validation" + el + "Shortcut") !== undefined) { 256 | // Are these custom validators? 257 | // Pull them out! 258 | $.each($this.data("validation" + el + "Shortcut").split(","), function(i2, el2) { 259 | newValidatorNamesToInspect.push(el2); 260 | }); 261 | } else if (settings.builtInValidators[el.toLowerCase()]) { 262 | // Is this a recognised built-in? 263 | // Pull it out! 264 | var validator = settings.builtInValidators[el.toLowerCase()]; 265 | if (validator.type.toLowerCase() === "shortcut") { 266 | $.each(validator.shortcut.split(","), function (i, el) { 267 | el = formatValidatorName(el); 268 | newValidatorNamesToInspect.push(el); 269 | validatorNames.push(el); 270 | }); 271 | } 272 | } 273 | }); 274 | 275 | validatorNamesToInspect = newValidatorNamesToInspect; 276 | 277 | } while (validatorNamesToInspect.length > 0) 278 | 279 | // ============================================================= 280 | // SET UP VALIDATOR ARRAYS 281 | // ============================================================= 282 | 283 | var validators = {}; 284 | 285 | $.each(validatorNames, function (i, el) { 286 | // Set up the 'override' message 287 | var message = $this.data("validation" + el + "Message"); 288 | var hasOverrideMessage = (message !== undefined); 289 | var foundValidator = false; 290 | message = 291 | ( 292 | message 293 | ? message 294 | : "'" + el + "' validation failed " 295 | ) 296 | ; 297 | 298 | $.each( 299 | settings.validatorTypes, 300 | function (validatorType, validatorTemplate) { 301 | if (validators[validatorType] === undefined) { 302 | validators[validatorType] = []; 303 | } 304 | if (!foundValidator && $this.data("validation" + el + formatValidatorName(validatorTemplate.name)) !== undefined) { 305 | validators[validatorType].push( 306 | $.extend( 307 | true, 308 | { 309 | name: formatValidatorName(validatorTemplate.name), 310 | message: message 311 | }, 312 | validatorTemplate.init($this, el) 313 | ) 314 | ); 315 | foundValidator = true; 316 | } 317 | } 318 | ); 319 | 320 | if (!foundValidator && settings.builtInValidators[el.toLowerCase()]) { 321 | 322 | var validator = $.extend(true, {}, settings.builtInValidators[el.toLowerCase()]); 323 | if (hasOverrideMessage) { 324 | validator.message = message; 325 | } 326 | var validatorType = validator.type.toLowerCase(); 327 | 328 | if (validatorType === "shortcut") { 329 | foundValidator = true; 330 | } else { 331 | $.each( 332 | settings.validatorTypes, 333 | function (validatorTemplateType, validatorTemplate) { 334 | if (validators[validatorTemplateType] === undefined) { 335 | validators[validatorTemplateType] = []; 336 | } 337 | if (!foundValidator && validatorType === validatorTemplateType.toLowerCase()) { 338 | $this.data("validation" + el + formatValidatorName(validatorTemplate.name), validator[validatorTemplate.name.toLowerCase()]); 339 | validators[validatorType].push( 340 | $.extend( 341 | validator, 342 | validatorTemplate.init($this, el) 343 | ) 344 | ); 345 | foundValidator = true; 346 | } 347 | } 348 | ); 349 | } 350 | } 351 | 352 | if (! foundValidator) { 353 | $.error("Cannot find validation info for '" + el + "'"); 354 | } 355 | }); 356 | 357 | // ============================================================= 358 | // STORE FALLBACK VALUES 359 | // ============================================================= 360 | 361 | $helpBlock.data( 362 | "original-contents", 363 | ( 364 | $helpBlock.data("original-contents") 365 | ? $helpBlock.data("original-contents") 366 | : $helpBlock.html() 367 | ) 368 | ); 369 | 370 | $helpBlock.data( 371 | "original-role", 372 | ( 373 | $helpBlock.data("original-role") 374 | ? $helpBlock.data("original-role") 375 | : $helpBlock.attr("role") 376 | ) 377 | ); 378 | 379 | $controlGroup.data( 380 | "original-classes", 381 | ( 382 | $controlGroup.data("original-clases") 383 | ? $controlGroup.data("original-classes") 384 | : $controlGroup.attr("class") 385 | ) 386 | ); 387 | 388 | $this.data( 389 | "original-aria-invalid", 390 | ( 391 | $this.data("original-aria-invalid") 392 | ? $this.data("original-aria-invalid") 393 | : $this.attr("aria-invalid") 394 | ) 395 | ); 396 | 397 | // ============================================================= 398 | // VALIDATION 399 | // ============================================================= 400 | 401 | $this.bind( 402 | "validation.validation", 403 | function (event, params) { 404 | 405 | var value = getValue($this); 406 | 407 | // Get a list of the errors to apply 408 | var errorsFound = []; 409 | 410 | $.each(validators, function (validatorType, validatorTypeArray) { 411 | if (value || value.length || (params && params.includeEmpty) || (!!settings.validatorTypes[validatorType].blockSubmit && params && !!params.submitting)) { 412 | $.each(validatorTypeArray, function (i, validator) { 413 | if (settings.validatorTypes[validatorType].validate($this, value, validator)) { 414 | errorsFound.push(validator.message); 415 | } 416 | }); 417 | } 418 | }); 419 | 420 | return errorsFound; 421 | } 422 | ); 423 | 424 | $this.bind( 425 | "getValidators.validation", 426 | function () { 427 | return validators; 428 | } 429 | ); 430 | 431 | // ============================================================= 432 | // WATCH FOR CHANGES 433 | // ============================================================= 434 | $this.bind( 435 | "submit.validation", 436 | function () { 437 | return $this.triggerHandler("change.validation", {submitting: true}); 438 | } 439 | ); 440 | $this.bind( 441 | [ 442 | "keyup", 443 | "focus", 444 | "blur", 445 | "click", 446 | "keydown", 447 | "keypress", 448 | "change" 449 | ].join(".validation ") + ".validation", 450 | function (e, params) { 451 | 452 | var value = getValue($this); 453 | 454 | var errorsFound = []; 455 | 456 | $controlGroup.find("input,textarea,select").each(function (i, el) { 457 | var oldCount = errorsFound.length; 458 | $.each($(el).triggerHandler("validation.validation", params), function (j, message) { 459 | errorsFound.push(message); 460 | }); 461 | if (errorsFound.length > oldCount) { 462 | $(el).attr("aria-invalid", "true"); 463 | } else { 464 | var original = $this.data("original-aria-invalid"); 465 | $(el).attr("aria-invalid", (original !== undefined ? original : false)); 466 | } 467 | }); 468 | 469 | $form.find("input,select,textarea").not($this).not("[name=\"" + $this.attr("name") + "\"]").trigger("validationLostFocus.validation"); 470 | 471 | errorsFound = $.unique(errorsFound.sort()); 472 | 473 | // Were there any errors? 474 | if (errorsFound.length) { 475 | // Better flag it up as a warning. 476 | $controlGroup.removeClass("success error").addClass("warning"); 477 | 478 | // How many errors did we find? 479 | if (settings.options.semanticallyStrict && errorsFound.length === 1) { 480 | // Only one? Being strict? Just output it. 481 | $helpBlock.html(errorsFound[0] + 482 | ( settings.options.prependExistingHelpBlock ? $helpBlock.data("original-contents") : "" )); 483 | } else { 484 | // Multiple? Being sloppy? Glue them together into an UL. 485 | $helpBlock.html("
  • " + errorsFound.join("
  • ") + "
" + 486 | ( settings.options.prependExistingHelpBlock ? $helpBlock.data("original-contents") : "" )); 487 | } 488 | } else { 489 | $controlGroup.removeClass("warning error success"); 490 | if (value.length > 0) { 491 | $controlGroup.addClass("success"); 492 | } 493 | $helpBlock.html($helpBlock.data("original-contents")); 494 | } 495 | 496 | if (e.type === "blur") { 497 | $controlGroup.removeClass("success"); 498 | } 499 | } 500 | ); 501 | $this.bind("validationLostFocus.validation", function () { 502 | $controlGroup.removeClass("success"); 503 | }); 504 | }); 505 | }, 506 | destroy : function( ) { 507 | 508 | return this.each( 509 | function() { 510 | 511 | var 512 | $this = $(this), 513 | $controlGroup = $this.parents(".control-group").first(), 514 | $helpBlock = $controlGroup.find(".help-block").first(); 515 | 516 | // remove our events 517 | $this.unbind('.validation'); // events are namespaced. 518 | // reset help text 519 | $helpBlock.html($helpBlock.data("original-contents")); 520 | // reset classes 521 | $controlGroup.attr("class", $controlGroup.data("original-classes")); 522 | // reset aria 523 | $this.attr("aria-invalid", $this.data("original-aria-invalid")); 524 | // reset role 525 | $helpBlock.attr("role", $this.data("original-role")); 526 | // remove all elements we created 527 | if (createdElements.indexOf($helpBlock[0]) > -1) { 528 | $helpBlock.remove(); 529 | } 530 | 531 | } 532 | ); 533 | 534 | }, 535 | collectErrors : function(includeEmpty) { 536 | 537 | var errorMessages = {}; 538 | this.each(function (i, el) { 539 | var $el = $(el); 540 | var name = $el.attr("name"); 541 | var errors = $el.triggerHandler("validation.validation", {includeEmpty: true}); 542 | errorMessages[name] = $.extend(true, errors, errorMessages[name]); 543 | }); 544 | 545 | $.each(errorMessages, function (i, el) { 546 | if (el.length === 0) { 547 | delete errorMessages[i]; 548 | } 549 | }); 550 | 551 | return errorMessages; 552 | 553 | }, 554 | hasErrors: function() { 555 | 556 | var errorMessages = []; 557 | 558 | this.each(function (i, el) { 559 | errorMessages = errorMessages.concat( 560 | $(el).triggerHandler("getValidators.validation") ? $(el).triggerHandler("validation.validation", {submitting: true}) : [] 561 | ); 562 | }); 563 | 564 | return (errorMessages.length > 0); 565 | }, 566 | override : function (newDefaults) { 567 | defaults = $.extend(true, defaults, newDefaults); 568 | } 569 | }, 570 | validatorTypes: { 571 | callback: { 572 | name: "callback", 573 | init: function ($this, name) { 574 | return { 575 | validatorName: name, 576 | callback: $this.data("validation" + name + "Callback"), 577 | lastValue: $this.val(), 578 | lastValid: true, 579 | lastFinished: true 580 | }; 581 | }, 582 | validate: function ($this, value, validator) { 583 | if (validator.lastValue === value && validator.lastFinished) { 584 | return !validator.lastValid; 585 | } 586 | 587 | if (validator.lastFinished === true) 588 | { 589 | validator.lastValue = value; 590 | validator.lastValid = true; 591 | validator.lastFinished = false; 592 | 593 | var rrjqbvValidator = validator; 594 | var rrjqbvThis = $this; 595 | executeFunctionByName( 596 | validator.callback, 597 | window, 598 | $this, 599 | value, 600 | function (data) { 601 | if (rrjqbvValidator.lastValue === data.value) { 602 | rrjqbvValidator.lastValid = data.valid; 603 | if (data.message) { 604 | rrjqbvValidator.message = data.message; 605 | } 606 | rrjqbvValidator.lastFinished = true; 607 | rrjqbvThis.data("validation" + rrjqbvValidator.validatorName + "Message", rrjqbvValidator.message); 608 | // Timeout is set to avoid problems with the events being considered 'already fired' 609 | setTimeout(function () { 610 | rrjqbvThis.trigger("change.validation"); 611 | }, 1); // doesn't need a long timeout, just long enough for the event bubble to burst 612 | } 613 | } 614 | ); 615 | } 616 | 617 | return false; 618 | 619 | } 620 | }, 621 | ajax: { 622 | name: "ajax", 623 | init: function ($this, name) { 624 | return { 625 | validatorName: name, 626 | url: $this.data("validation" + name + "Ajax"), 627 | lastValue: $this.val(), 628 | lastValid: true, 629 | lastFinished: true 630 | }; 631 | }, 632 | validate: function ($this, value, validator) { 633 | if (""+validator.lastValue === ""+value && validator.lastFinished === true) { 634 | return validator.lastValid === false; 635 | } 636 | 637 | if (validator.lastFinished === true) 638 | { 639 | validator.lastValue = value; 640 | validator.lastValid = true; 641 | validator.lastFinished = false; 642 | $.ajax({ 643 | url: validator.url, 644 | data: "value=" + value + "&field=" + $this.attr("name"), 645 | dataType: "json", 646 | success: function (data) { 647 | if (""+validator.lastValue === ""+data.value) { 648 | validator.lastValid = !!(data.valid); 649 | if (data.message) { 650 | validator.message = data.message; 651 | } 652 | validator.lastFinished = true; 653 | $this.data("validation" + validator.validatorName + "Message", validator.message); 654 | // Timeout is set to avoid problems with the events being considered 'already fired' 655 | setTimeout(function () { 656 | $this.trigger("change.validation"); 657 | }, 1); // doesn't need a long timeout, just long enough for the event bubble to burst 658 | } 659 | }, 660 | failure: function () { 661 | validator.lastValid = true; 662 | validator.message = "ajax call failed"; 663 | validator.lastFinished = true; 664 | $this.data("validation" + validator.validatorName + "Message", validator.message); 665 | // Timeout is set to avoid problems with the events being considered 'already fired' 666 | setTimeout(function () { 667 | $this.trigger("change.validation"); 668 | }, 1); // doesn't need a long timeout, just long enough for the event bubble to burst 669 | } 670 | }); 671 | } 672 | 673 | return false; 674 | 675 | } 676 | }, 677 | regex: { 678 | name: "regex", 679 | init: function ($this, name) { 680 | return {regex: regexFromString($this.data("validation" + name + "Regex"))}; 681 | }, 682 | validate: function ($this, value, validator) { 683 | return (!validator.regex.test(value) && ! validator.negative) 684 | || (validator.regex.test(value) && validator.negative); 685 | } 686 | }, 687 | required: { 688 | name: "required", 689 | init: function ($this, name) { 690 | return {}; 691 | }, 692 | validate: function ($this, value, validator) { 693 | return !!(value.length === 0 && ! validator.negative) 694 | || !!(value.length > 0 && validator.negative); 695 | }, 696 | blockSubmit: true 697 | }, 698 | match: { 699 | name: "match", 700 | init: function ($this, name) { 701 | var element = $this.parents("form").first().find("[name=\"" + $this.data("validation" + name + "Match") + "\"]").first(); 702 | element.bind("validation.validation", function () { 703 | $this.trigger("change.validation", {submitting: true}); 704 | }); 705 | return {"element": element}; 706 | }, 707 | validate: function ($this, value, validator) { 708 | return (value !== validator.element.val() && ! validator.negative) 709 | || (value === validator.element.val() && validator.negative); 710 | }, 711 | blockSubmit: true 712 | }, 713 | max: { 714 | name: "max", 715 | init: function ($this, name) { 716 | return {max: $this.data("validation" + name + "Max")}; 717 | }, 718 | validate: function ($this, value, validator) { 719 | return (parseFloat(value, 10) > parseFloat(validator.max, 10) && ! validator.negative) 720 | || (parseFloat(value, 10) <= parseFloat(validator.max, 10) && validator.negative); 721 | } 722 | }, 723 | min: { 724 | name: "min", 725 | init: function ($this, name) { 726 | return {min: $this.data("validation" + name + "Min")}; 727 | }, 728 | validate: function ($this, value, validator) { 729 | return (parseFloat(value) < parseFloat(validator.min) && ! validator.negative) 730 | || (parseFloat(value) >= parseFloat(validator.min) && validator.negative); 731 | } 732 | }, 733 | maxlength: { 734 | name: "maxlength", 735 | init: function ($this, name) { 736 | return {maxlength: $this.data("validation" + name + "Maxlength")}; 737 | }, 738 | validate: function ($this, value, validator) { 739 | return ((value.length > validator.maxlength) && ! validator.negative) 740 | || ((value.length <= validator.maxlength) && validator.negative); 741 | } 742 | }, 743 | minlength: { 744 | name: "minlength", 745 | init: function ($this, name) { 746 | return {minlength: $this.data("validation" + name + "Minlength")}; 747 | }, 748 | validate: function ($this, value, validator) { 749 | return ((value.length < validator.minlength) && ! validator.negative) 750 | || ((value.length >= validator.minlength) && validator.negative); 751 | } 752 | }, 753 | maxchecked: { 754 | name: "maxchecked", 755 | init: function ($this, name) { 756 | var elements = $this.parents("form").first().find("[name=\"" + $this.attr("name") + "\"]"); 757 | elements.bind("click.validation", function () { 758 | $this.trigger("change.validation", {includeEmpty: true}); 759 | }); 760 | return {maxchecked: $this.data("validation" + name + "Maxchecked"), elements: elements}; 761 | }, 762 | validate: function ($this, value, validator) { 763 | return (validator.elements.filter(":checked").length > validator.maxchecked && ! validator.negative) 764 | || (validator.elements.filter(":checked").length <= validator.maxchecked && validator.negative); 765 | }, 766 | blockSubmit: true 767 | }, 768 | minchecked: { 769 | name: "minchecked", 770 | init: function ($this, name) { 771 | var elements = $this.parents("form").first().find("[name=\"" + $this.attr("name") + "\"]"); 772 | elements.bind("click.validation", function () { 773 | $this.trigger("change.validation", {includeEmpty: true}); 774 | }); 775 | return {minchecked: $this.data("validation" + name + "Minchecked"), elements: elements}; 776 | }, 777 | validate: function ($this, value, validator) { 778 | return (validator.elements.filter(":checked").length < validator.minchecked && ! validator.negative) 779 | || (validator.elements.filter(":checked").length >= validator.minchecked && validator.negative); 780 | }, 781 | blockSubmit: true 782 | } 783 | }, 784 | builtInValidators: { 785 | email: { 786 | name: "Email", 787 | type: "shortcut", 788 | shortcut: "validemail" 789 | }, 790 | validemail: { 791 | name: "Validemail", 792 | type: "regex", 793 | regex: "[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\\\.[A-Za-z]{2,4}", 794 | message: "Not a valid email address" 795 | }, 796 | passwordagain: { 797 | name: "Passwordagain", 798 | type: "match", 799 | match: "password", 800 | message: "Does not match the given password" 801 | }, 802 | positive: { 803 | name: "Positive", 804 | type: "shortcut", 805 | shortcut: "number,positivenumber" 806 | }, 807 | negative: { 808 | name: "Negative", 809 | type: "shortcut", 810 | shortcut: "number,negativenumber" 811 | }, 812 | number: { 813 | name: "Number", 814 | type: "regex", 815 | regex: "([+-]?\\\d+(\\\.\\\d*)?([eE][+-]?[0-9]+)?)?", 816 | message: "Must be a number" 817 | }, 818 | integer: { 819 | name: "Integer", 820 | type: "regex", 821 | regex: "[+-]?\\\d+", 822 | message: "No decimal places allowed" 823 | }, 824 | positivenumber: { 825 | name: "Positivenumber", 826 | type: "min", 827 | min: 0, 828 | message: "Must be a positive number" 829 | }, 830 | negativenumber: { 831 | name: "Negativenumber", 832 | type: "max", 833 | max: 0, 834 | message: "Must be a negative number" 835 | }, 836 | required: { 837 | name: "Required", 838 | type: "required", 839 | message: "This is required" 840 | }, 841 | checkone: { 842 | name: "Checkone", 843 | type: "minchecked", 844 | minchecked: 1, 845 | message: "Check at least one option" 846 | } 847 | } 848 | }; 849 | 850 | var formatValidatorName = function (name) { 851 | return name 852 | .toLowerCase() 853 | .replace( 854 | /(^|\s)([a-z])/g , 855 | function(m,p1,p2) { 856 | return p1+p2.toUpperCase(); 857 | } 858 | ) 859 | ; 860 | }; 861 | 862 | var getValue = function ($this) { 863 | // Extract the value we're talking about 864 | var value = $this.val(); 865 | var type = $this.attr("type"); 866 | if (type === "checkbox") { 867 | value = ($this.is(":checked") ? value : ""); 868 | } 869 | if (type === "radio") { 870 | value = ($('input[name="' + $this.attr("name") + '"]:checked').length > 0 ? value : ""); 871 | } 872 | return value; 873 | }; 874 | 875 | function regexFromString(inputstring) { 876 | return new RegExp("^" + inputstring + "$"); 877 | } 878 | 879 | /** 880 | * Thanks to Jason Bunting via StackOverflow.com 881 | * 882 | * http://stackoverflow.com/questions/359788/how-to-execute-a-javascript-function-when-i-have-its-name-as-a-string#answer-359910 883 | * Short link: http://tinyurl.com/executeFunctionByName 884 | **/ 885 | function executeFunctionByName(functionName, context /*, args*/) { 886 | var args = Array.prototype.slice.call(arguments).splice(2); 887 | var namespaces = functionName.split("."); 888 | var func = namespaces.pop(); 889 | for(var i = 0; i < namespaces.length; i++) { 890 | context = context[namespaces[i]]; 891 | } 892 | return context[func].apply(this, args); 893 | } 894 | 895 | $.fn.jqBootstrapValidation = function( method ) { 896 | 897 | if ( defaults.methods[method] ) { 898 | return defaults.methods[method].apply( this, Array.prototype.slice.call( arguments, 1 )); 899 | } else if ( typeof method === 'object' || ! method ) { 900 | return defaults.methods.init.apply( this, arguments ); 901 | } else { 902 | $.error( 'Method ' + method + ' does not exist on jQuery.jqBootstrapValidation' ); 903 | return null; 904 | } 905 | 906 | }; 907 | 908 | $.jqBootstrapValidation = function (options) { 909 | $(":input").not("[type=image],[type=submit]").jqBootstrapValidation.apply(this,arguments); 910 | }; 911 | 912 | })( jQuery ); 913 | --------------------------------------------------------------------------------